xref: /freebsd/sys/amd64/amd64/mem.c (revision 56ae44c5df2441d65d54ac4e9c5d89cd0ff779b9)
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  *
3956ae44c5SDavid E. O'Brien  *	Utah $Hdr: mem.c 1.13 89/10/08$
4056ae44c5SDavid E. O'Brien  *	@(#)mem.c	7.2 (Berkeley) 5/9/91
415b81b6b3SRodney W. Grimes  */
425b81b6b3SRodney W. Grimes 
4356ae44c5SDavid E. O'Brien #include <sys/cdefs.h>
4456ae44c5SDavid E. O'Brien __FBSDID("$FreeBSD$");
4556ae44c5SDavid E. O'Brien 
465b81b6b3SRodney W. Grimes /*
475b81b6b3SRodney W. Grimes  * Memory special file
485b81b6b3SRodney W. Grimes  */
495b81b6b3SRodney W. Grimes 
5026f9a767SRodney W. Grimes #include <sys/param.h>
5126f9a767SRodney W. Grimes #include <sys/conf.h>
52265cdeddSBruce Evans #include <sys/fcntl.h>
534ffd949eSMike Smith #include <sys/ioccom.h>
54d4af7a50SDavid E. O'Brien #include <sys/kernel.h>
5523955314SAlfred Perlstein #include <sys/lock.h>
5626f9a767SRodney W. Grimes #include <sys/malloc.h>
574ffd949eSMike Smith #include <sys/memrange.h>
589dceb26bSJohn Baldwin #include <sys/mutex.h>
5926f9a767SRodney W. Grimes #include <sys/proc.h>
60bb25f0ddSBruce Evans #include <sys/signalvar.h>
61d4af7a50SDavid E. O'Brien #include <sys/systm.h>
62d4af7a50SDavid E. O'Brien #include <sys/uio.h>
635b81b6b3SRodney W. Grimes 
645afffbaaSMark Murray #include <machine/db_machdep.h>
65d1d9d260SBruce Evans #include <machine/frame.h>
6626f9a767SRodney W. Grimes #include <machine/psl.h>
674ffd949eSMike Smith #include <machine/specialreg.h>
683c9a3c9cSPeter Wemm #include <machine/vmparam.h>
695b81b6b3SRodney W. Grimes 
70c87801feSDavid Greenman #include <vm/vm.h>
7126f9a767SRodney W. Grimes #include <vm/pmap.h>
72efeaf95aSDavid Greenman #include <vm/vm_extern.h>
735b81b6b3SRodney W. Grimes 
745afffbaaSMark Murray static dev_t memdev, kmemdev, iodev;
7587f6c662SJulian Elischer 
7687f6c662SJulian Elischer static	d_open_t	mmopen;
7787f6c662SJulian Elischer static	d_close_t	mmclose;
78c73feca0SBruce Evans static	d_read_t	mmrw;
7987f6c662SJulian Elischer static	d_ioctl_t	mmioctl;
8087f6c662SJulian Elischer static	d_mmap_t	memmmap;
8187f6c662SJulian Elischer 
8253ac6efbSJulian Elischer #define CDEV_MAJOR 2
834e2f199eSPoul-Henning Kamp static struct cdevsw mem_cdevsw = {
847ac40f5fSPoul-Henning Kamp 	.d_open =	mmopen,
857ac40f5fSPoul-Henning Kamp 	.d_close =	mmclose,
867ac40f5fSPoul-Henning Kamp 	.d_read =	mmrw,
877ac40f5fSPoul-Henning Kamp 	.d_write =	mmrw,
887ac40f5fSPoul-Henning Kamp 	.d_ioctl =	mmioctl,
897ac40f5fSPoul-Henning Kamp 	.d_mmap =	memmmap,
907ac40f5fSPoul-Henning Kamp 	.d_name =	"mem",
917ac40f5fSPoul-Henning Kamp 	.d_maj =	CDEV_MAJOR,
927ac40f5fSPoul-Henning Kamp 	.d_flags =	D_MEM,
934e2f199eSPoul-Henning Kamp };
9453ac6efbSJulian Elischer 
954ffd949eSMike Smith MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors");
964ffd949eSMike Smith 
974ffd949eSMike Smith struct mem_range_softc mem_range_softc;
984ffd949eSMike Smith 
9987f6c662SJulian Elischer static int
100b40ce416SJulian Elischer mmclose(dev_t dev, int flags, int fmt, struct thread *td)
10178d172caSRodney W. Grimes {
10278d172caSRodney W. Grimes 	switch (minor(dev)) {
10378d172caSRodney W. Grimes 	case 14:
104afa88623SPeter Wemm 		td->td_frame->tf_rflags &= ~PSL_IOPL;
10578d172caSRodney W. Grimes 	}
10678d172caSRodney W. Grimes 	return (0);
10778d172caSRodney W. Grimes }
10833f538b9SBruce Evans 
10987f6c662SJulian Elischer static int
110b40ce416SJulian Elischer mmopen(dev_t dev, int flags, int fmt, struct thread *td)
11178d172caSRodney W. Grimes {
112da3df630SBruce Evans 	int error;
11378d172caSRodney W. Grimes 
11478d172caSRodney W. Grimes 	switch (minor(dev)) {
11518284c94SPoul-Henning Kamp 	case 0:
11618284c94SPoul-Henning Kamp 	case 1:
1171851c8fdSRobert Watson 		if (flags & FWRITE) {
118a854ed98SJohn Baldwin 			error = securelevel_gt(td->td_ucred, 0);
1191851c8fdSRobert Watson 			if (error != 0)
1201851c8fdSRobert Watson 				return (error);
1211851c8fdSRobert Watson 		}
12218284c94SPoul-Henning Kamp 		break;
12378d172caSRodney W. Grimes 	case 14:
12444731cabSJohn Baldwin 		error = suser(td);
125da3df630SBruce Evans 		if (error != 0)
126da3df630SBruce Evans 			return (error);
127a854ed98SJohn Baldwin 		error = securelevel_gt(td->td_ucred, 0);
1281851c8fdSRobert Watson 		if (error != 0)
1291851c8fdSRobert Watson 			return (error);
130afa88623SPeter Wemm 		td->td_frame->tf_rflags |= PSL_IOPL;
13178d172caSRodney W. Grimes 		break;
13278d172caSRodney W. Grimes 	}
13378d172caSRodney W. Grimes 	return (0);
13478d172caSRodney W. Grimes }
13533f538b9SBruce Evans 
1365afffbaaSMark Murray /*ARGSUSED*/
13787f6c662SJulian Elischer static int
1385afffbaaSMark Murray mmrw(dev_t dev, struct uio *uio, int flags)
1395b81b6b3SRodney W. Grimes {
1405afffbaaSMark Murray 	int o;
141afa88623SPeter Wemm 	u_long c = 0, v;
1425afffbaaSMark Murray 	struct iovec *iov;
1435b81b6b3SRodney W. Grimes 	int error = 0;
1445afffbaaSMark Murray 	vm_offset_t addr, eaddr;
1455b81b6b3SRodney W. Grimes 
1460cddd8f0SMatthew Dillon 	GIANT_REQUIRED;
1470cddd8f0SMatthew Dillon 
1485b81b6b3SRodney W. Grimes 	while (uio->uio_resid > 0 && error == 0) {
1495b81b6b3SRodney W. Grimes 		iov = uio->uio_iov;
1505b81b6b3SRodney W. Grimes 		if (iov->iov_len == 0) {
1515b81b6b3SRodney W. Grimes 			uio->uio_iov++;
1525b81b6b3SRodney W. Grimes 			uio->uio_iovcnt--;
1535b81b6b3SRodney W. Grimes 			if (uio->uio_iovcnt < 0)
1545b81b6b3SRodney W. Grimes 				panic("mmrw");
1555b81b6b3SRodney W. Grimes 			continue;
1565b81b6b3SRodney W. Grimes 		}
1575b81b6b3SRodney W. Grimes 		switch (minor(dev)) {
1585b81b6b3SRodney W. Grimes 
1595b81b6b3SRodney W. Grimes /* minor device 0 is physical memory */
1605b81b6b3SRodney W. Grimes 		case 0:
1615b81b6b3SRodney W. Grimes 			v = uio->uio_offset;
162bfcd2ec7SHidetoshi Shimokawa kmemphys:
163bfcd2ec7SHidetoshi Shimokawa 			o = v & PAGE_MASK;
164bfcd2ec7SHidetoshi Shimokawa 			c = min(uio->uio_resid, (u_int)(PAGE_SIZE - o));
165bfcd2ec7SHidetoshi Shimokawa 			error = uiomove((void *)PHYS_TO_DMAP(v), (int)c, uio);
1665b81b6b3SRodney W. Grimes 			continue;
1675b81b6b3SRodney W. Grimes 
1685b81b6b3SRodney W. Grimes /* minor device 1 is kernel memory */
1695afffbaaSMark Murray 		case 1:
170bfcd2ec7SHidetoshi Shimokawa 			v = uio->uio_offset;
17197e11262SDavid Greenman 
172bfcd2ec7SHidetoshi Shimokawa 			if (v >= DMAP_MIN_ADDRESS && v < DMAP_MAX_ADDRESS) {
173bfcd2ec7SHidetoshi Shimokawa 				v = DMAP_TO_PHYS(v);
174bfcd2ec7SHidetoshi Shimokawa 				goto kmemphys;
175bfcd2ec7SHidetoshi Shimokawa 			}
176bfcd2ec7SHidetoshi Shimokawa 
177bfcd2ec7SHidetoshi Shimokawa 			c = iov->iov_len;
17897e11262SDavid Greenman 			/*
17997e11262SDavid Greenman 			 * Make sure that all of the pages are currently resident so
18097e11262SDavid Greenman 			 * that we don't create any zero-fill pages.
18197e11262SDavid Greenman 			 */
182bfcd2ec7SHidetoshi Shimokawa 			addr = trunc_page(v);
183bfcd2ec7SHidetoshi Shimokawa 			eaddr = round_page(v + c);
184d021fc11SPeter Wemm 
1853c9a3c9cSPeter Wemm 			if (addr < (vm_offset_t)KERNBASE)
186e40ab3e9SMark Murray 				return (EFAULT);
18797e11262SDavid Greenman 			for (; addr < eaddr; addr += PAGE_SIZE)
188e40ab3e9SMark Murray 				if (pmap_extract(kernel_pmap, addr) == 0)
189e40ab3e9SMark Murray 					return (EFAULT);
19097e11262SDavid Greenman 
191bfcd2ec7SHidetoshi Shimokawa 			if (!kernacc((caddr_t)(long)v, c,
19202c58685SPoul-Henning Kamp 			    uio->uio_rw == UIO_READ ?
193e40ab3e9SMark Murray 			    VM_PROT_READ : VM_PROT_WRITE))
1945b81b6b3SRodney W. Grimes 				return (EFAULT);
195bfcd2ec7SHidetoshi Shimokawa 
196bfcd2ec7SHidetoshi Shimokawa 			error = uiomove((caddr_t)(long)v, (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
218227f9a1cSJake Burkholder memmmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, 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:
22507159f9cSMaxime Henrion 		*paddr = offset;
22607159f9cSMaxime Henrion 		break;
227b513c262SDavid Greenman 
228b513c262SDavid Greenman 	/* minor device 1 is kernel memory */
229b513c262SDavid Greenman 	case 1:
23007159f9cSMaxime Henrion         	*paddr = vtophys(offset);
23107159f9cSMaxime Henrion 		break;
232493c240cSMark Murray 
233493c240cSMark Murray 	default:
234e40ab3e9SMark Murray 		return (-1);
235b513c262SDavid Greenman 	}
23607159f9cSMaxime Henrion 	return (0);
2378567cb9fSMark Murray }
238b513c262SDavid Greenman 
239316bbd5cSBruce Evans /*
2404ffd949eSMike Smith  * Operations for changing memory attributes.
2414ffd949eSMike Smith  *
2424ffd949eSMike Smith  * This is basically just an ioctl shim for mem_range_attr_get
2434ffd949eSMike Smith  * and mem_range_attr_set.
2444ffd949eSMike Smith  */
2454ffd949eSMike Smith static int
246b40ce416SJulian Elischer mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td)
2474ffd949eSMike Smith {
2484ffd949eSMike Smith 	int nd, error = 0;
2494ffd949eSMike Smith 	struct mem_range_op *mo = (struct mem_range_op *)data;
2504ffd949eSMike Smith 	struct mem_range_desc *md;
2514ffd949eSMike Smith 
2524ffd949eSMike Smith 	/* is this for us? */
2534ffd949eSMike Smith 	if ((cmd != MEMRANGE_GET) &&
2544ffd949eSMike Smith 	    (cmd != MEMRANGE_SET))
2554871de2fSBrian Feldman 		return (ENOTTY);
2564ffd949eSMike Smith 
2574ffd949eSMike Smith 	/* any chance we can handle this? */
2584ffd949eSMike Smith 	if (mem_range_softc.mr_op == NULL)
2594ffd949eSMike Smith 		return (EOPNOTSUPP);
2604ffd949eSMike Smith 
2614ffd949eSMike Smith 	/* do we have any descriptors? */
2624ffd949eSMike Smith 	if (mem_range_softc.mr_ndesc == 0)
2634ffd949eSMike Smith 		return (ENXIO);
2644ffd949eSMike Smith 
2654ffd949eSMike Smith 	switch (cmd) {
2664ffd949eSMike Smith 	case MEMRANGE_GET:
2674ffd949eSMike Smith 		nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc);
2684ffd949eSMike Smith 		if (nd > 0) {
2694ffd949eSMike Smith 			md = (struct mem_range_desc *)
2704ffd949eSMike Smith 				malloc(nd * sizeof(struct mem_range_desc),
271a163d034SWarner Losh 				       M_MEMDESC, M_WAITOK);
272ac3595b0SMike Smith 			error = mem_range_attr_get(md, &nd);
273ac3595b0SMike Smith 			if (!error)
2744ffd949eSMike Smith 				error = copyout(md, mo->mo_desc,
2754ffd949eSMike Smith 					nd * sizeof(struct mem_range_desc));
2764ffd949eSMike Smith 			free(md, M_MEMDESC);
2774ffd949eSMike Smith 		}
278e40ab3e9SMark Murray 		else
279e40ab3e9SMark Murray 			nd = mem_range_softc.mr_ndesc;
2804ffd949eSMike Smith 		mo->mo_arg[0] = nd;
2814ffd949eSMike Smith 		break;
2824ffd949eSMike Smith 
2834ffd949eSMike Smith 	case MEMRANGE_SET:
2844ffd949eSMike Smith 		md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc),
285a163d034SWarner Losh 						    M_MEMDESC, M_WAITOK);
2864ffd949eSMike Smith 		error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc));
2874ffd949eSMike Smith 		/* clamp description string */
2884ffd949eSMike Smith 		md->mr_owner[sizeof(md->mr_owner) - 1] = 0;
2894ffd949eSMike Smith 		if (error == 0)
2904ffd949eSMike Smith 			error = mem_range_attr_set(md, &mo->mo_arg[0]);
2914ffd949eSMike Smith 		free(md, M_MEMDESC);
2924ffd949eSMike Smith 		break;
2934ffd949eSMike Smith 	}
2944ffd949eSMike Smith 	return (error);
2954ffd949eSMike Smith }
2964ffd949eSMike Smith 
2974ffd949eSMike Smith /*
2984ffd949eSMike Smith  * Implementation-neutral, kernel-callable functions for manipulating
2994ffd949eSMike Smith  * memory range attributes.
3004ffd949eSMike Smith  */
301ac3595b0SMike Smith int
3025afffbaaSMark Murray mem_range_attr_get(struct mem_range_desc *mrd, int *arg)
3034ffd949eSMike Smith {
3044af396a5SMike Smith 	/* can we handle this? */
3054af396a5SMike Smith 	if (mem_range_softc.mr_op == NULL)
3064af396a5SMike Smith 		return (EOPNOTSUPP);
3074af396a5SMike Smith 
308e40ab3e9SMark Murray 	if (*arg == 0)
3094ffd949eSMike Smith 		*arg = mem_range_softc.mr_ndesc;
310e40ab3e9SMark Murray 	else
3115afffbaaSMark Murray 		bcopy(mem_range_softc.mr_desc, mrd,
3125afffbaaSMark Murray 			(*arg) * sizeof(struct mem_range_desc));
313ac3595b0SMike Smith 	return (0);
3144ffd949eSMike Smith }
3154ffd949eSMike Smith 
3164ffd949eSMike Smith int
3175afffbaaSMark Murray mem_range_attr_set(struct mem_range_desc *mrd, int *arg)
3184ffd949eSMike Smith {
3194af396a5SMike Smith 	/* can we handle this? */
3204af396a5SMike Smith 	if (mem_range_softc.mr_op == NULL)
3214af396a5SMike Smith 		return (EOPNOTSUPP);
3224af396a5SMike Smith 
3234ffd949eSMike Smith 	return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg));
3244ffd949eSMike Smith }
3254ffd949eSMike Smith 
3264ffd949eSMike Smith static int
3275afffbaaSMark Murray mem_modevent(module_t mod, int type, void *data)
3284ffd949eSMike Smith {
3295afffbaaSMark Murray 	switch(type) {
3305afffbaaSMark Murray 	case MOD_LOAD:
3315afffbaaSMark Murray 		if (bootverbose)
3325afffbaaSMark Murray 			printf("mem: <memory & I/O>\n");
3334ffd949eSMike Smith 		/* Initialise memory range handling */
3344ffd949eSMike Smith 		if (mem_range_softc.mr_op != NULL)
3354ffd949eSMike Smith 			mem_range_softc.mr_op->init(&mem_range_softc);
3364ffd949eSMike Smith 
3375afffbaaSMark Murray 		memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM,
3385afffbaaSMark Murray 			0640, "mem");
3395afffbaaSMark Murray 		kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM,
3405afffbaaSMark Murray 			0640, "kmem");
3415afffbaaSMark Murray 		iodev = make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL,
3425afffbaaSMark Murray 			0600, "io");
343e40ab3e9SMark Murray 		return (0);
3445afffbaaSMark Murray 
3455afffbaaSMark Murray 	case MOD_UNLOAD:
3465afffbaaSMark Murray 		destroy_dev(memdev);
3475afffbaaSMark Murray 		destroy_dev(kmemdev);
3485afffbaaSMark Murray 		destroy_dev(iodev);
349e40ab3e9SMark Murray 		return (0);
3505afffbaaSMark Murray 
3515afffbaaSMark Murray 	case MOD_SHUTDOWN:
352e40ab3e9SMark Murray 		return (0);
3535afffbaaSMark Murray 
3545afffbaaSMark Murray 	default:
355e40ab3e9SMark Murray 		return (EOPNOTSUPP);
3565afffbaaSMark Murray 	}
3577198bf47SJulian Elischer }
35853ac6efbSJulian Elischer 
3595afffbaaSMark Murray DEV_MODULE(mem, mem_modevent, NULL);
360