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