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