8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright (c) 2015, Joyent, Inc. All rights reserved.
28 */
29
30 /*
31 * Memory special file
32 */
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/user.h>
37 #include <sys/buf.h>
38 #include <sys/systm.h>
39 #include <sys/cred.h>
40 #include <sys/vm.h>
41 #include <sys/uio.h>
42 #include <sys/mman.h>
43 #include <sys/kmem.h>
44 #include <vm/seg.h>
45 #include <vm/page.h>
46 #include <sys/stat.h>
47 #include <sys/vmem.h>
143 }
144
145 /*ARGSUSED1*/
146 static int
147 mm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
148 {
149 int i;
150 struct mem_minor {
151 char *name;
152 minor_t minor;
153 int privonly;
154 const char *rdpriv;
155 const char *wrpriv;
156 mode_t priv_mode;
157 } mm[] = {
158 { "mem", M_MEM, 0, NULL, "all", 0640 },
159 { "kmem", M_KMEM, 0, NULL, "all", 0640 },
160 { "allkmem", M_ALLKMEM, 0, "all", "all", 0600 },
161 { "null", M_NULL, PRIVONLY_DEV, NULL, NULL, 0666 },
162 { "zero", M_ZERO, PRIVONLY_DEV, NULL, NULL, 0666 },
163 };
164 kstat_t *ksp;
165
166 mutex_init(&mm_lock, NULL, MUTEX_DEFAULT, NULL);
167 mm_map = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
168
169 for (i = 0; i < (sizeof (mm) / sizeof (mm[0])); i++) {
170 if (ddi_create_priv_minor_node(devi, mm[i].name, S_IFCHR,
171 mm[i].minor, DDI_PSEUDO, mm[i].privonly,
172 mm[i].rdpriv, mm[i].wrpriv, mm[i].priv_mode) ==
173 DDI_FAILURE) {
174 ddi_remove_minor_node(devi, NULL);
175 return (DDI_FAILURE);
176 }
177 }
178
179 mm_dip = devi;
180
181 ksp = kstat_create("mm", 0, "phys_installed", "misc",
182 KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_VIRTUAL);
204 *result = (void *)mm_dip;
205 error = DDI_SUCCESS;
206 break;
207 case DDI_INFO_DEVT2INSTANCE:
208 *result = (void *)0;
209 error = DDI_SUCCESS;
210 break;
211 default:
212 error = DDI_FAILURE;
213 }
214 return (error);
215 }
216
217 /*ARGSUSED1*/
218 static int
219 mmopen(dev_t *devp, int flag, int typ, struct cred *cred)
220 {
221 switch (getminor(*devp)) {
222 case M_NULL:
223 case M_ZERO:
224 case M_MEM:
225 case M_KMEM:
226 case M_ALLKMEM:
227 /* standard devices */
228 break;
229
230 default:
231 /* Unsupported or unknown type */
232 return (EINVAL);
233 }
234 /* must be character device */
235 if (typ != OTYP_CHR)
236 return (EINVAL);
237 return (0);
238 }
239
240 struct pollhead mm_pollhd;
241
242 /*ARGSUSED*/
243 static int
244 mmchpoll(dev_t dev, short events, int anyyet, short *reventsp,
245 struct pollhead **phpp)
246 {
247 switch (getminor(dev)) {
248 case M_NULL:
249 case M_ZERO:
250 case M_MEM:
251 case M_KMEM:
252 case M_ALLKMEM:
253 *reventsp = events & (POLLIN | POLLOUT | POLLPRI | POLLRDNORM |
254 POLLWRNORM | POLLRDBAND | POLLWRBAND);
255 /*
256 * A non NULL pollhead pointer should be returned in case
257 * user polls for 0 events.
258 */
259 *phpp = !anyyet && !*reventsp ?
260 &mm_pollhd : (struct pollhead *)NULL;
261 return (0);
262 default:
263 /* no other devices currently support polling */
264 return (ENXIO);
265 }
266 }
267
268 static int
269 mmpropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags,
421 v = hat_getpfnum(kas.a_hat,
422 (caddr_t)(uintptr_t)uio->uio_loffset);
423 if (v == PFN_INVALID) {
424 if (locked)
425 as_pageunlock(&kas, ppp, vaddr,
426 PAGESIZE, S_WRITE);
427 error = EFAULT;
428 break;
429 }
430
431 error = mmio(uio, rw, v, uio->uio_loffset & PAGEOFFSET,
432 minor == M_ALLKMEM || mm_kmem_io_access,
433 (locked && ppp) ? *ppp : NULL);
434 if (locked)
435 as_pageunlock(&kas, ppp, vaddr, PAGESIZE,
436 S_WRITE);
437 }
438
439 break;
440
441 case M_ZERO:
442 if (rw == UIO_READ) {
443 label_t ljb;
444
445 if (on_fault(&ljb)) {
446 no_fault();
447 error = EFAULT;
448 break;
449 }
450 uzero(iov->iov_base, iov->iov_len);
451 no_fault();
452 uio->uio_resid -= iov->iov_len;
453 uio->uio_loffset += iov->iov_len;
454 break;
455 }
456 /* else it's a write, fall through to NULL case */
457 /*FALLTHROUGH*/
458
459 case M_NULL:
460 if (rw == UIO_READ)
810
811 switch (minor) {
812 case M_MEM:
813 pf = btop(off);
814 memlist_read_lock();
815 for (pmem = phys_install; pmem != NULL; pmem = pmem->ml_next) {
816 if (pf >= BTOP(pmem->ml_address) &&
817 pf < BTOP(pmem->ml_address + pmem->ml_size)) {
818 memlist_read_unlock();
819 return (impl_obmem_pfnum(pf));
820 }
821 }
822 memlist_read_unlock();
823 break;
824
825 case M_KMEM:
826 case M_ALLKMEM:
827 /* no longer supported with KPR */
828 return (-1);
829
830 case M_ZERO:
831 /*
832 * We shouldn't be mmap'ing to /dev/zero here as
833 * mmsegmap() should have already converted
834 * a mapping request for this device to a mapping
835 * using seg_vn for anonymous memory.
836 */
837 break;
838
839 }
840 return (-1);
841 }
842
843 /*
844 * This function is called when a memory device is mmap'ed.
845 * Set up the mapping to the correct device driver.
846 */
847 static int
848 mmsegmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
849 uint_t prot, uint_t maxprot, uint_t flags, struct cred *cred)
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright (c) 2015, Joyent, Inc. All rights reserved.
28 * Copyright 2017 James S Blachly, MD <james.blachly@gmail.com>
29 */
30
31 /*
32 * Memory special file
33 */
34
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/user.h>
38 #include <sys/buf.h>
39 #include <sys/systm.h>
40 #include <sys/cred.h>
41 #include <sys/vm.h>
42 #include <sys/uio.h>
43 #include <sys/mman.h>
44 #include <sys/kmem.h>
45 #include <vm/seg.h>
46 #include <vm/page.h>
47 #include <sys/stat.h>
48 #include <sys/vmem.h>
144 }
145
146 /*ARGSUSED1*/
147 static int
148 mm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
149 {
150 int i;
151 struct mem_minor {
152 char *name;
153 minor_t minor;
154 int privonly;
155 const char *rdpriv;
156 const char *wrpriv;
157 mode_t priv_mode;
158 } mm[] = {
159 { "mem", M_MEM, 0, NULL, "all", 0640 },
160 { "kmem", M_KMEM, 0, NULL, "all", 0640 },
161 { "allkmem", M_ALLKMEM, 0, "all", "all", 0600 },
162 { "null", M_NULL, PRIVONLY_DEV, NULL, NULL, 0666 },
163 { "zero", M_ZERO, PRIVONLY_DEV, NULL, NULL, 0666 },
164 { "full", M_FULL, PRIVONLY_DEV, NULL, NULL, 0666 },
165 };
166 kstat_t *ksp;
167
168 mutex_init(&mm_lock, NULL, MUTEX_DEFAULT, NULL);
169 mm_map = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
170
171 for (i = 0; i < (sizeof (mm) / sizeof (mm[0])); i++) {
172 if (ddi_create_priv_minor_node(devi, mm[i].name, S_IFCHR,
173 mm[i].minor, DDI_PSEUDO, mm[i].privonly,
174 mm[i].rdpriv, mm[i].wrpriv, mm[i].priv_mode) ==
175 DDI_FAILURE) {
176 ddi_remove_minor_node(devi, NULL);
177 return (DDI_FAILURE);
178 }
179 }
180
181 mm_dip = devi;
182
183 ksp = kstat_create("mm", 0, "phys_installed", "misc",
184 KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_VIRTUAL);
206 *result = (void *)mm_dip;
207 error = DDI_SUCCESS;
208 break;
209 case DDI_INFO_DEVT2INSTANCE:
210 *result = (void *)0;
211 error = DDI_SUCCESS;
212 break;
213 default:
214 error = DDI_FAILURE;
215 }
216 return (error);
217 }
218
219 /*ARGSUSED1*/
220 static int
221 mmopen(dev_t *devp, int flag, int typ, struct cred *cred)
222 {
223 switch (getminor(*devp)) {
224 case M_NULL:
225 case M_ZERO:
226 case M_FULL:
227 case M_MEM:
228 case M_KMEM:
229 case M_ALLKMEM:
230 /* standard devices */
231 break;
232
233 default:
234 /* Unsupported or unknown type */
235 return (EINVAL);
236 }
237 /* must be character device */
238 if (typ != OTYP_CHR)
239 return (EINVAL);
240 return (0);
241 }
242
243 struct pollhead mm_pollhd;
244
245 /*ARGSUSED*/
246 static int
247 mmchpoll(dev_t dev, short events, int anyyet, short *reventsp,
248 struct pollhead **phpp)
249 {
250 switch (getminor(dev)) {
251 case M_NULL:
252 case M_ZERO:
253 case M_FULL:
254 case M_MEM:
255 case M_KMEM:
256 case M_ALLKMEM:
257 *reventsp = events & (POLLIN | POLLOUT | POLLPRI | POLLRDNORM |
258 POLLWRNORM | POLLRDBAND | POLLWRBAND);
259 /*
260 * A non NULL pollhead pointer should be returned in case
261 * user polls for 0 events.
262 */
263 *phpp = !anyyet && !*reventsp ?
264 &mm_pollhd : (struct pollhead *)NULL;
265 return (0);
266 default:
267 /* no other devices currently support polling */
268 return (ENXIO);
269 }
270 }
271
272 static int
273 mmpropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags,
425 v = hat_getpfnum(kas.a_hat,
426 (caddr_t)(uintptr_t)uio->uio_loffset);
427 if (v == PFN_INVALID) {
428 if (locked)
429 as_pageunlock(&kas, ppp, vaddr,
430 PAGESIZE, S_WRITE);
431 error = EFAULT;
432 break;
433 }
434
435 error = mmio(uio, rw, v, uio->uio_loffset & PAGEOFFSET,
436 minor == M_ALLKMEM || mm_kmem_io_access,
437 (locked && ppp) ? *ppp : NULL);
438 if (locked)
439 as_pageunlock(&kas, ppp, vaddr, PAGESIZE,
440 S_WRITE);
441 }
442
443 break;
444
445 case M_FULL:
446 if (rw == UIO_WRITE) {
447 error = ENOSPC;
448 break;
449 }
450 /* else it's a read, fall through to zero case */
451 /*FALLTHROUGH*/
452
453 case M_ZERO:
454 if (rw == UIO_READ) {
455 label_t ljb;
456
457 if (on_fault(&ljb)) {
458 no_fault();
459 error = EFAULT;
460 break;
461 }
462 uzero(iov->iov_base, iov->iov_len);
463 no_fault();
464 uio->uio_resid -= iov->iov_len;
465 uio->uio_loffset += iov->iov_len;
466 break;
467 }
468 /* else it's a write, fall through to NULL case */
469 /*FALLTHROUGH*/
470
471 case M_NULL:
472 if (rw == UIO_READ)
822
823 switch (minor) {
824 case M_MEM:
825 pf = btop(off);
826 memlist_read_lock();
827 for (pmem = phys_install; pmem != NULL; pmem = pmem->ml_next) {
828 if (pf >= BTOP(pmem->ml_address) &&
829 pf < BTOP(pmem->ml_address + pmem->ml_size)) {
830 memlist_read_unlock();
831 return (impl_obmem_pfnum(pf));
832 }
833 }
834 memlist_read_unlock();
835 break;
836
837 case M_KMEM:
838 case M_ALLKMEM:
839 /* no longer supported with KPR */
840 return (-1);
841
842 case M_FULL:
843 case M_ZERO:
844 /*
845 * We shouldn't be mmap'ing to /dev/zero here as
846 * mmsegmap() should have already converted
847 * a mapping request for this device to a mapping
848 * using seg_vn for anonymous memory.
849 */
850 break;
851
852 }
853 return (-1);
854 }
855
856 /*
857 * This function is called when a memory device is mmap'ed.
858 * Set up the mapping to the correct device driver.
859 */
860 static int
861 mmsegmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
862 uint_t prot, uint_t maxprot, uint_t flags, struct cred *cred)
|