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