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