xref: /titanic_41/usr/src/uts/common/io/mem.c (revision 4f85d229295a756a4e6f1759b47df7b97412db7d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Memory special file
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/user.h>
36 #include <sys/buf.h>
37 #include <sys/systm.h>
38 #include <sys/cred.h>
39 #include <sys/vm.h>
40 #include <sys/uio.h>
41 #include <sys/mman.h>
42 #include <sys/kmem.h>
43 #include <vm/seg.h>
44 #include <vm/page.h>
45 #include <sys/stat.h>
46 #include <sys/vmem.h>
47 #include <sys/memlist.h>
48 #include <sys/bootconf.h>
49 
50 #include <vm/seg_vn.h>
51 #include <vm/seg_dev.h>
52 #include <vm/seg_kmem.h>
53 #include <vm/seg_kp.h>
54 #include <vm/seg_kpm.h>
55 #include <vm/hat.h>
56 
57 #include <sys/conf.h>
58 #include <sys/mem.h>
59 #include <sys/types.h>
60 #include <sys/conf.h>
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/errno.h>
64 #include <sys/modctl.h>
65 #include <sys/memlist.h>
66 #include <sys/ddi.h>
67 #include <sys/sunddi.h>
68 #include <sys/debug.h>
69 
70 #ifdef __sparc
71 extern int cpu_get_mem_name(uint64_t, uint64_t *, uint64_t, char *, int, int *);
72 extern int cpu_get_mem_info(uint64_t, uint64_t, uint64_t *, uint64_t *,
73     uint64_t *, int *, int *, int *);
74 extern size_t cpu_get_name_bufsize(void);
75 #endif
76 
77 /*
78  * Turn a byte length into a pagecount.  The DDI btop takes a
79  * 32-bit size on 32-bit machines, this handles 64-bit sizes for
80  * large physical-memory 32-bit machines.
81  */
82 #define	BTOP(x)	((pgcnt_t)((x) >> _pageshift))
83 
84 static kmutex_t mm_lock;
85 static caddr_t mm_map;
86 
87 static dev_info_t *mm_dip;	/* private copy of devinfo pointer */
88 
89 static int mm_kmem_io_access;
90 
91 static int mm_kstat_update(kstat_t *ksp, int rw);
92 static int mm_kstat_snapshot(kstat_t *ksp, void *buf, int rw);
93 
94 /*ARGSUSED1*/
95 static int
96 mm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
97 {
98 	int i;
99 	struct mem_minor {
100 		char *name;
101 		minor_t minor;
102 		int privonly;
103 		const char *rdpriv;
104 		const char *wrpriv;
105 		mode_t priv_mode;
106 	} mm[] = {
107 		{ "mem",	M_MEM,		0,	NULL,	"all",	0640 },
108 		{ "kmem",	M_KMEM,		0,	NULL,	"all",	0640 },
109 		{ "allkmem",	M_ALLKMEM,	0,	"all",	"all",	0600 },
110 		{ "null",	M_NULL,	PRIVONLY_DEV,	NULL,	NULL,	0666 },
111 		{ "zero",	M_ZERO, PRIVONLY_DEV,	NULL,	NULL,	0666 },
112 	};
113 	kstat_t *ksp;
114 
115 	mutex_init(&mm_lock, NULL, MUTEX_DEFAULT, NULL);
116 	mm_map = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
117 
118 	for (i = 0; i < (sizeof (mm) / sizeof (mm[0])); i++) {
119 		if (ddi_create_priv_minor_node(devi, mm[i].name, S_IFCHR,
120 		    mm[i].minor, DDI_PSEUDO, mm[i].privonly,
121 		    mm[i].rdpriv, mm[i].wrpriv, mm[i].priv_mode) ==
122 		    DDI_FAILURE) {
123 			ddi_remove_minor_node(devi, NULL);
124 			return (DDI_FAILURE);
125 		}
126 	}
127 
128 	mm_dip = devi;
129 
130 	ksp = kstat_create("mm", 0, "phys_installed", "misc",
131 	    KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_VIRTUAL);
132 	if (ksp != NULL) {
133 		ksp->ks_update = mm_kstat_update;
134 		ksp->ks_snapshot = mm_kstat_snapshot;
135 		ksp->ks_lock = &mm_lock; /* XXX - not really needed */
136 		kstat_install(ksp);
137 	}
138 
139 	mm_kmem_io_access = ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
140 	    "kmem_io_access", 0);
141 
142 	return (DDI_SUCCESS);
143 }
144 
145 /*ARGSUSED*/
146 static int
147 mm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
148 {
149 	register int error;
150 
151 	switch (infocmd) {
152 	case DDI_INFO_DEVT2DEVINFO:
153 		*result = (void *)mm_dip;
154 		error = DDI_SUCCESS;
155 		break;
156 	case DDI_INFO_DEVT2INSTANCE:
157 		*result = (void *)0;
158 		error = DDI_SUCCESS;
159 		break;
160 	default:
161 		error = DDI_FAILURE;
162 	}
163 	return (error);
164 }
165 
166 /*ARGSUSED1*/
167 static int
168 mmopen(dev_t *devp, int flag, int typ, struct cred *cred)
169 {
170 	switch (getminor(*devp)) {
171 	case M_NULL:
172 	case M_ZERO:
173 	case M_MEM:
174 	case M_KMEM:
175 	case M_ALLKMEM:
176 		/* standard devices */
177 		break;
178 
179 	default:
180 		/* Unsupported or unknown type */
181 		return (EINVAL);
182 	}
183 	return (0);
184 }
185 
186 struct pollhead	mm_pollhd;
187 
188 /*ARGSUSED*/
189 static int
190 mmchpoll(dev_t dev, short events, int anyyet, short *reventsp,
191     struct pollhead **phpp)
192 {
193 	switch (getminor(dev)) {
194 	case M_NULL:
195 	case M_ZERO:
196 	case M_MEM:
197 	case M_KMEM:
198 	case M_ALLKMEM:
199 		*reventsp = events & (POLLIN | POLLOUT | POLLPRI | POLLRDNORM |
200 			POLLWRNORM | POLLRDBAND | POLLWRBAND);
201 		/*
202 		 * A non NULL pollhead pointer should be returned in case
203 		 * user polls for 0 events.
204 		 */
205 		*phpp = !anyyet && !*reventsp ?
206 		    &mm_pollhd : (struct pollhead *)NULL;
207 		return (0);
208 	default:
209 		/* no other devices currently support polling */
210 		return (ENXIO);
211 	}
212 }
213 
214 static int
215 mmpropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags,
216     char *name, caddr_t valuep, int *lengthp)
217 {
218 	/*
219 	 * implement zero size to reduce overhead (avoid two failing
220 	 * property lookups per stat).
221 	 */
222 	return (ddi_prop_op_size(dev, dip, prop_op,
223 	    flags, name, valuep, lengthp, 0));
224 }
225 
226 static int
227 mmio(struct uio *uio, enum uio_rw rw, pfn_t pfn, off_t pageoff, int allowio)
228 {
229 	int error = 0;
230 	size_t nbytes = MIN((size_t)(PAGESIZE - pageoff),
231 	    (size_t)uio->uio_iov->iov_len);
232 
233 	mutex_enter(&mm_lock);
234 	hat_devload(kas.a_hat, mm_map, PAGESIZE, pfn,
235 	    (uint_t)(rw == UIO_READ ? PROT_READ : PROT_READ | PROT_WRITE),
236 	    HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK);
237 
238 	if (!pf_is_memory(pfn)) {
239 		if (allowio) {
240 			size_t c = uio->uio_iov->iov_len;
241 
242 			if (ddi_peekpokeio(NULL, uio, rw,
243 			    (caddr_t)(uintptr_t)uio->uio_loffset, c,
244 			    sizeof (int32_t)) != DDI_SUCCESS)
245 				error = EFAULT;
246 		} else
247 			error = EIO;
248 	} else
249 		error = uiomove(&mm_map[pageoff], nbytes, rw, uio);
250 
251 	hat_unload(kas.a_hat, mm_map, PAGESIZE, HAT_UNLOAD_UNLOCK);
252 	mutex_exit(&mm_lock);
253 	return (error);
254 }
255 
256 #ifdef	__sparc
257 
258 static int
259 mmpagelock(struct as *as, caddr_t va)
260 {
261 	struct seg *seg;
262 	int i;
263 
264 	AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
265 	seg = as_segat(as, va);
266 	i = (seg != NULL)? SEGOP_CAPABLE(seg, S_CAPABILITY_NOMINFLT) : 0;
267 	AS_LOCK_EXIT(as, &as->a_lock);
268 
269 	return (i);
270 }
271 
272 #define	NEED_LOCK_KVADDR(kva)	mmpagelock(&kas, kva)
273 
274 #else	/* __i386, __amd64 */
275 
276 #define	NEED_LOCK_KVADDR(va)	0
277 
278 #endif	/* __sparc */
279 
280 /*ARGSUSED3*/
281 static int
282 mmrw(dev_t dev, struct uio *uio, enum uio_rw rw, cred_t *cred)
283 {
284 	pfn_t v;
285 	struct iovec *iov;
286 	int error = 0;
287 	size_t c;
288 	ssize_t oresid = uio->uio_resid;
289 	minor_t minor = getminor(dev);
290 
291 	while (uio->uio_resid > 0 && error == 0) {
292 		iov = uio->uio_iov;
293 		if (iov->iov_len == 0) {
294 			uio->uio_iov++;
295 			uio->uio_iovcnt--;
296 			if (uio->uio_iovcnt < 0)
297 				panic("mmrw");
298 			continue;
299 		}
300 		switch (minor) {
301 
302 		case M_MEM:
303 			memlist_read_lock();
304 			if (!address_in_memlist(phys_install,
305 			    (uint64_t)uio->uio_loffset, 1)) {
306 				memlist_read_unlock();
307 				error = EFAULT;
308 				break;
309 			}
310 			memlist_read_unlock();
311 
312 			v = BTOP((u_offset_t)uio->uio_loffset);
313 			error = mmio(uio, rw, v,
314 			    uio->uio_loffset & PAGEOFFSET, 0);
315 			break;
316 
317 		case M_KMEM:
318 		case M_ALLKMEM:
319 			{
320 			page_t **ppp;
321 			caddr_t vaddr = (caddr_t)uio->uio_offset;
322 			int try_lock = NEED_LOCK_KVADDR(vaddr);
323 			int locked = 0;
324 
325 			/*
326 			 * If vaddr does not map a valid page, as_pagelock()
327 			 * will return failure. Hence we can't check the
328 			 * return value and return EFAULT here as we'd like.
329 			 * seg_kp and seg_kpm do not properly support
330 			 * as_pagelock() for this context so we avoid it
331 			 * using the try_lock set check above.  Some day when
332 			 * the kernel page locking gets redesigned all this
333 			 * muck can be cleaned up.
334 			 */
335 			if (try_lock)
336 				locked = (as_pagelock(&kas, &ppp, vaddr,
337 				    PAGESIZE, S_WRITE) == 0);
338 
339 			v = hat_getpfnum(kas.a_hat,
340 			    (caddr_t)(uintptr_t)uio->uio_loffset);
341 			if (v == PFN_INVALID) {
342 				if (locked)
343 					as_pageunlock(&kas, ppp, vaddr,
344 					    PAGESIZE, S_WRITE);
345 				error = EFAULT;
346 				break;
347 			}
348 
349 			error = mmio(uio, rw, v, uio->uio_loffset & PAGEOFFSET,
350 			    minor == M_ALLKMEM || mm_kmem_io_access);
351 			if (locked)
352 				as_pageunlock(&kas, ppp, vaddr, PAGESIZE,
353 				    S_WRITE);
354 			}
355 
356 			break;
357 
358 		case M_ZERO:
359 			if (rw == UIO_READ) {
360 				label_t ljb;
361 
362 				if (on_fault(&ljb)) {
363 					no_fault();
364 					error = EFAULT;
365 					break;
366 				}
367 				uzero(iov->iov_base, iov->iov_len);
368 				no_fault();
369 				uio->uio_resid -= iov->iov_len;
370 				uio->uio_loffset += iov->iov_len;
371 				break;
372 			}
373 			/* else it's a write, fall through to NULL case */
374 			/*FALLTHROUGH*/
375 
376 		case M_NULL:
377 			if (rw == UIO_READ)
378 				return (0);
379 			c = iov->iov_len;
380 			iov->iov_base += c;
381 			iov->iov_len -= c;
382 			uio->uio_loffset += c;
383 			uio->uio_resid -= c;
384 			break;
385 
386 		}
387 	}
388 	return (uio->uio_resid == oresid ? error : 0);
389 }
390 
391 static int
392 mmread(dev_t dev, struct uio *uio, cred_t *cred)
393 {
394 	return (mmrw(dev, uio, UIO_READ, cred));
395 }
396 
397 static int
398 mmwrite(dev_t dev, struct uio *uio, cred_t *cred)
399 {
400 	return (mmrw(dev, uio, UIO_WRITE, cred));
401 }
402 
403 /*
404  * Private ioctl for libkvm to support kvm_physaddr().
405  * Given an address space and a VA, compute the PA.
406  */
407 static int
408 mmioctl_vtop(intptr_t data)
409 {
410 	mem_vtop_t mem_vtop;
411 	proc_t *p;
412 	pfn_t pfn = (pfn_t)PFN_INVALID;
413 	pid_t pid = 0;
414 	struct as *as;
415 	struct seg *seg;
416 
417 	if (copyin((void *)data, &mem_vtop, sizeof (mem_vtop_t)))
418 		return (EFAULT);
419 	if (mem_vtop.m_as == &kas) {
420 		pfn = hat_getpfnum(kas.a_hat, mem_vtop.m_va);
421 	} else if (mem_vtop.m_as == NULL) {
422 		return (EIO);
423 	} else {
424 		mutex_enter(&pidlock);
425 		for (p = practive; p != NULL; p = p->p_next) {
426 			if (p->p_as == mem_vtop.m_as) {
427 				pid = p->p_pid;
428 				break;
429 			}
430 		}
431 		mutex_exit(&pidlock);
432 		if (p == NULL)
433 			return (EIO);
434 		p = sprlock(pid);
435 		if (p == NULL)
436 			return (EIO);
437 		as = p->p_as;
438 		if (as == mem_vtop.m_as) {
439 			mutex_exit(&p->p_lock);
440 			AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
441 			for (seg = AS_SEGFIRST(as); seg != NULL;
442 			    seg = AS_SEGNEXT(as, seg))
443 				if ((uintptr_t)mem_vtop.m_va -
444 				    (uintptr_t)seg->s_base < seg->s_size)
445 					break;
446 			if (seg != NULL)
447 				pfn = hat_getpfnum(as->a_hat, mem_vtop.m_va);
448 			AS_LOCK_EXIT(as, &as->a_lock);
449 			mutex_enter(&p->p_lock);
450 		}
451 		sprunlock(p);
452 	}
453 	mem_vtop.m_pfn = pfn;
454 	if (pfn == PFN_INVALID)
455 		return (EIO);
456 	if (copyout(&mem_vtop, (void *)data, sizeof (mem_vtop_t)))
457 		return (EFAULT);
458 
459 	return (0);
460 }
461 
462 /*
463  * Given a PA, execute the given page retire command on it.
464  */
465 static int
466 mmioctl_page_retire(int cmd, intptr_t data)
467 {
468 	extern int page_retire_test(void);
469 	uint64_t pa;
470 
471 	if (copyin((void *)data, &pa, sizeof (uint64_t))) {
472 		return (EFAULT);
473 	}
474 
475 	switch (cmd) {
476 	case MEM_PAGE_ISRETIRED:
477 		return (page_retire_check(pa, NULL));
478 
479 	case MEM_PAGE_UNRETIRE:
480 		return (page_unretire(pa));
481 
482 	case MEM_PAGE_RETIRE:
483 		return (page_retire(pa, PR_FMA));
484 
485 	case MEM_PAGE_RETIRE_MCE:
486 		return (page_retire(pa, PR_MCE));
487 
488 	case MEM_PAGE_RETIRE_UE:
489 		return (page_retire(pa, PR_UE));
490 
491 	case MEM_PAGE_GETERRORS:
492 		{
493 			uint64_t page_errors;
494 			int rc = page_retire_check(pa, &page_errors);
495 			if (copyout(&page_errors, (void *)data,
496 			    sizeof (uint64_t))) {
497 				return (EFAULT);
498 			}
499 			return (rc);
500 		}
501 
502 	case MEM_PAGE_RETIRE_TEST:
503 		return (page_retire_test());
504 
505 	}
506 
507 	return (EINVAL);
508 }
509 
510 #ifdef __sparc
511 /*
512  * Given a syndrome, syndrome type, and address return the
513  * associated memory name in the provided data buffer.
514  */
515 static int
516 mmioctl_get_mem_name(intptr_t data)
517 {
518 	mem_name_t mem_name;
519 #ifdef	_SYSCALL32
520 	mem_name32_t mem_name32;
521 #endif
522 	void *buf;
523 	size_t bufsize;
524 	int len, err;
525 
526 	if ((bufsize = cpu_get_name_bufsize()) == 0)
527 		return (ENOTSUP);
528 
529 	if (get_udatamodel() == DATAMODEL_NATIVE) {
530 		if (copyin((void *)data, &mem_name, sizeof (mem_name_t)))
531 			return (EFAULT);
532 	}
533 #ifdef	_SYSCALL32
534 	else {
535 		if (copyin((void *)data, &mem_name32, sizeof (mem_name32_t)))
536 			return (EFAULT);
537 		mem_name.m_addr = mem_name32.m_addr;
538 		mem_name.m_synd = mem_name32.m_synd;
539 		mem_name.m_type[0] = mem_name32.m_type[0];
540 		mem_name.m_type[1] = mem_name32.m_type[1];
541 		mem_name.m_name = (caddr_t)(uintptr_t)mem_name32.m_name;
542 		mem_name.m_namelen = (size_t)mem_name32.m_namelen;
543 	}
544 #endif	/* _SYSCALL32 */
545 
546 	buf = kmem_alloc(bufsize, KM_SLEEP);
547 
548 	/*
549 	 * Call into cpu specific code to do the lookup.
550 	 */
551 	if ((err = cpu_get_mem_name(mem_name.m_synd, mem_name.m_type,
552 	    mem_name.m_addr, buf, bufsize, &len)) != 0) {
553 		kmem_free(buf, bufsize);
554 		return (err);
555 	}
556 
557 	if (len >= mem_name.m_namelen) {
558 		kmem_free(buf, bufsize);
559 		return (ENAMETOOLONG);
560 	}
561 
562 	if (copyoutstr(buf, (char *)mem_name.m_name,
563 	    mem_name.m_namelen, NULL) != 0) {
564 		kmem_free(buf, bufsize);
565 		return (EFAULT);
566 	}
567 
568 	kmem_free(buf, bufsize);
569 	return (0);
570 }
571 
572 /*
573  * Given a syndrome and address return information about the associated memory.
574  */
575 static int
576 mmioctl_get_mem_info(intptr_t data)
577 {
578 	mem_info_t mem_info;
579 	int err;
580 
581 	if (copyin((void *)data, &mem_info, sizeof (mem_info_t)))
582 		return (EFAULT);
583 
584 	if ((err = cpu_get_mem_info(mem_info.m_synd, mem_info.m_addr,
585 	    &mem_info.m_mem_size, &mem_info.m_seg_size, &mem_info.m_bank_size,
586 	    &mem_info.m_segments, &mem_info.m_banks, &mem_info.m_mcid)) != 0)
587 		return (err);
588 
589 	if (copyout(&mem_info, (void *)data, sizeof (mem_info_t)) != 0)
590 		return (EFAULT);
591 
592 	return (0);
593 }
594 #endif	/* __sparc */
595 
596 /*
597  * Private ioctls for
598  *	libkvm to support kvm_physaddr().
599  *	FMA support for page_retire() and memory attribute information.
600  */
601 /*ARGSUSED*/
602 static int
603 mmioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp)
604 {
605 	switch (cmd) {
606 	case MEM_VTOP:
607 		if (getminor(dev) != M_KMEM)
608 			return (ENXIO);
609 		return (mmioctl_vtop(data));
610 
611 	case MEM_PAGE_RETIRE:
612 	case MEM_PAGE_ISRETIRED:
613 	case MEM_PAGE_UNRETIRE:
614 	case MEM_PAGE_RETIRE_MCE:
615 	case MEM_PAGE_RETIRE_UE:
616 	case MEM_PAGE_GETERRORS:
617 	case MEM_PAGE_RETIRE_TEST:
618 		if (getminor(dev) != M_MEM)
619 			return (ENXIO);
620 		return (mmioctl_page_retire(cmd, data));
621 
622 	case MEM_NAME:
623 		if (getminor(dev) != M_MEM)
624 			return (ENXIO);
625 #ifdef __sparc
626 		return (mmioctl_get_mem_name(data));
627 #else
628 		return (ENOTSUP);
629 #endif
630 
631 	case MEM_INFO:
632 		if (getminor(dev) != M_MEM)
633 			return (ENXIO);
634 #ifdef __sparc
635 		return (mmioctl_get_mem_info(data));
636 #else
637 		return (ENOTSUP);
638 #endif
639 	}
640 	return (ENXIO);
641 }
642 
643 /*ARGSUSED2*/
644 static int
645 mmmmap(dev_t dev, off_t off, int prot)
646 {
647 	pfn_t pf;
648 	struct memlist *pmem;
649 	minor_t minor = getminor(dev);
650 
651 	switch (minor) {
652 	case M_MEM:
653 		pf = btop(off);
654 		memlist_read_lock();
655 		for (pmem = phys_install; pmem != NULL; pmem = pmem->next) {
656 			if (pf >= BTOP(pmem->address) &&
657 			    pf < BTOP(pmem->address + pmem->size)) {
658 				memlist_read_unlock();
659 				return (impl_obmem_pfnum(pf));
660 			}
661 		}
662 		memlist_read_unlock();
663 		break;
664 
665 	case M_KMEM:
666 	case M_ALLKMEM:
667 		/* no longer supported with KPR */
668 		return (-1);
669 
670 	case M_ZERO:
671 		/*
672 		 * We shouldn't be mmap'ing to /dev/zero here as
673 		 * mmsegmap() should have already converted
674 		 * a mapping request for this device to a mapping
675 		 * using seg_vn for anonymous memory.
676 		 */
677 		break;
678 
679 	}
680 	return (-1);
681 }
682 
683 /*
684  * This function is called when a memory device is mmap'ed.
685  * Set up the mapping to the correct device driver.
686  */
687 static int
688 mmsegmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
689     uint_t prot, uint_t maxprot, uint_t flags, struct cred *cred)
690 {
691 	struct segvn_crargs vn_a;
692 	struct segdev_crargs dev_a;
693 	int error;
694 	minor_t minor;
695 	off_t i;
696 
697 	minor = getminor(dev);
698 
699 	as_rangelock(as);
700 	if ((flags & MAP_FIXED) == 0) {
701 		/*
702 		 * No need to worry about vac alignment on /dev/zero
703 		 * since this is a "clone" object that doesn't yet exist.
704 		 */
705 		map_addr(addrp, len, (offset_t)off,
706 				(minor == M_MEM) || (minor == M_KMEM), flags);
707 
708 		if (*addrp == NULL) {
709 			as_rangeunlock(as);
710 			return (ENOMEM);
711 		}
712 	} else {
713 		/*
714 		 * User specified address -
715 		 * Blow away any previous mappings.
716 		 */
717 		(void) as_unmap(as, *addrp, len);
718 	}
719 
720 	switch (minor) {
721 	case M_MEM:
722 		/* /dev/mem cannot be mmap'ed with MAP_PRIVATE */
723 		if ((flags & MAP_TYPE) != MAP_SHARED) {
724 			as_rangeunlock(as);
725 			return (EINVAL);
726 		}
727 
728 		/*
729 		 * Check to ensure that the entire range is
730 		 * legal and we are not trying to map in
731 		 * more than the device will let us.
732 		 */
733 		for (i = 0; i < len; i += PAGESIZE) {
734 			if (mmmmap(dev, off + i, maxprot) == -1) {
735 				as_rangeunlock(as);
736 				return (ENXIO);
737 			}
738 		}
739 
740 		/*
741 		 * Use seg_dev segment driver for /dev/mem mapping.
742 		 */
743 		dev_a.mapfunc = mmmmap;
744 		dev_a.dev = dev;
745 		dev_a.offset = off;
746 		dev_a.type = (flags & MAP_TYPE);
747 		dev_a.prot = (uchar_t)prot;
748 		dev_a.maxprot = (uchar_t)maxprot;
749 		dev_a.hat_attr = 0;
750 
751 		/*
752 		 * Make /dev/mem mappings non-consistent since we can't
753 		 * alias pages that don't have page structs behind them,
754 		 * such as kernel stack pages. If someone mmap()s a kernel
755 		 * stack page and if we give him a tte with cv, a line from
756 		 * that page can get into both pages of the spitfire d$.
757 		 * But snoop from another processor will only invalidate
758 		 * the first page. This later caused kernel (xc_attention)
759 		 * to go into an infinite loop at pil 13 and no interrupts
760 		 * could come in. See 1203630.
761 		 *
762 		 */
763 		dev_a.hat_flags = HAT_LOAD_NOCONSIST;
764 		dev_a.devmap_data = NULL;
765 
766 		error = as_map(as, *addrp, len, segdev_create, &dev_a);
767 		break;
768 
769 	case M_ZERO:
770 		/*
771 		 * Use seg_vn segment driver for /dev/zero mapping.
772 		 * Passing in a NULL amp gives us the "cloning" effect.
773 		 */
774 		vn_a.vp = NULL;
775 		vn_a.offset = 0;
776 		vn_a.type = (flags & MAP_TYPE);
777 		vn_a.prot = prot;
778 		vn_a.maxprot = maxprot;
779 		vn_a.flags = flags & ~MAP_TYPE;
780 		vn_a.cred = cred;
781 		vn_a.amp = NULL;
782 		vn_a.szc = 0;
783 		vn_a.lgrp_mem_policy_flags = 0;
784 		error = as_map(as, *addrp, len, segvn_create, &vn_a);
785 		break;
786 
787 	case M_KMEM:
788 	case M_ALLKMEM:
789 		/* No longer supported with KPR. */
790 		error = ENXIO;
791 		break;
792 
793 	case M_NULL:
794 		/*
795 		 * Use seg_dev segment driver for /dev/null mapping.
796 		 */
797 		dev_a.mapfunc = mmmmap;
798 		dev_a.dev = dev;
799 		dev_a.offset = off;
800 		dev_a.type = 0;		/* neither PRIVATE nor SHARED */
801 		dev_a.prot = dev_a.maxprot = (uchar_t)PROT_NONE;
802 		dev_a.hat_attr = 0;
803 		dev_a.hat_flags = 0;
804 		error = as_map(as, *addrp, len, segdev_create, &dev_a);
805 		break;
806 
807 	default:
808 		error = ENXIO;
809 	}
810 
811 	as_rangeunlock(as);
812 	return (error);
813 }
814 
815 static struct cb_ops mm_cb_ops = {
816 	mmopen,			/* open */
817 	nulldev,		/* close */
818 	nodev,			/* strategy */
819 	nodev,			/* print */
820 	nodev,			/* dump */
821 	mmread,			/* read */
822 	mmwrite,		/* write */
823 	mmioctl,		/* ioctl */
824 	nodev,			/* devmap */
825 	mmmmap,			/* mmap */
826 	mmsegmap,		/* segmap */
827 	mmchpoll,		/* poll */
828 	mmpropop,		/* prop_op */
829 	0,			/* streamtab  */
830 	D_NEW | D_MP | D_64BIT | D_U64BIT
831 };
832 
833 static struct dev_ops mm_ops = {
834 	DEVO_REV,		/* devo_rev, */
835 	0,			/* refcnt  */
836 	mm_info,		/* get_dev_info */
837 	nulldev,		/* identify */
838 	nulldev,		/* probe */
839 	mm_attach,		/* attach */
840 	nodev,			/* detach */
841 	nodev,			/* reset */
842 	&mm_cb_ops,		/* driver operations */
843 	(struct bus_ops *)0	/* bus operations */
844 };
845 
846 static struct modldrv modldrv = {
847 	&mod_driverops, "memory driver %I%", &mm_ops,
848 };
849 
850 static struct modlinkage modlinkage = {
851 	MODREV_1, &modldrv, NULL
852 };
853 
854 int
855 _init(void)
856 {
857 	return (mod_install(&modlinkage));
858 }
859 
860 int
861 _info(struct modinfo *modinfop)
862 {
863 	return (mod_info(&modlinkage, modinfop));
864 }
865 
866 int
867 _fini(void)
868 {
869 	return (mod_remove(&modlinkage));
870 }
871 
872 static int
873 mm_kstat_update(kstat_t *ksp, int rw)
874 {
875 	struct memlist *pmem;
876 	uint_t count;
877 
878 	if (rw == KSTAT_WRITE)
879 		return (EACCES);
880 
881 	count = 0;
882 	memlist_read_lock();
883 	for (pmem = phys_install; pmem != NULL; pmem = pmem->next) {
884 		count++;
885 	}
886 	memlist_read_unlock();
887 
888 	ksp->ks_ndata = count;
889 	ksp->ks_data_size = count * 2 * sizeof (uint64_t);
890 
891 	return (0);
892 }
893 
894 static int
895 mm_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
896 {
897 	struct memlist *pmem;
898 	struct memunit {
899 		uint64_t address;
900 		uint64_t size;
901 	} *kspmem;
902 
903 	if (rw == KSTAT_WRITE)
904 		return (EACCES);
905 
906 	ksp->ks_snaptime = gethrtime();
907 
908 	kspmem = (struct memunit *)buf;
909 	memlist_read_lock();
910 	for (pmem = phys_install; pmem != NULL; pmem = pmem->next, kspmem++) {
911 		if ((caddr_t)kspmem >= (caddr_t)buf + ksp->ks_data_size)
912 			break;
913 		kspmem->address = pmem->address;
914 		kspmem->size = pmem->size;
915 	}
916 	memlist_read_unlock();
917 
918 	return (0);
919 }
920