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