/* * Copyright (c) 1988 University of Utah. * Copyright (c) 1982, 1986, 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * %sccs.include.redist.c% * * from: Utah $Hdr: mem.c 1.14 90/10/12$ * * @(#)mem.c 8.2 (Berkeley) 11/14/93 */ /* * Memory special file */ #include #include #include #include #include #include #include #include #include #include extern u_int lowram; caddr_t zeropage; /*ARGSUSED*/ mmrw(dev, uio, flags) dev_t dev; struct uio *uio; int flags; { register int o; register u_int c, v; register struct iovec *iov; int error = 0; int kernloc; while (uio->uio_resid > 0 && error == 0) { iov = uio->uio_iov; if (iov->iov_len == 0) { uio->uio_iov++; uio->uio_iovcnt--; if (uio->uio_iovcnt < 0) panic("mmrw"); continue; } switch (minor(dev)) { /* minor device 0 is physical memory */ case 0: v = uio->uio_offset; #ifndef DEBUG /* allow reads only in RAM (except for DEBUG) */ if (v >= 0xFFFFFFFC || v < lowram) return (EFAULT); #endif pmap_enter(kernel_pmap, (vm_offset_t)vmmap, trunc_page(v), uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE, TRUE); o = (int)uio->uio_offset & PGOFSET; c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET)); c = min(c, (u_int)(NBPG - o)); c = min(c, (u_int)iov->iov_len); error = uiomove((caddr_t)&vmmap[o], (int)c, uio); pmap_remove(kernel_pmap, (vm_offset_t)vmmap, (vm_offset_t)&vmmap[NBPG]); continue; /* minor device 1 is kernel memory */ case 1: kernloc = uio->uio_offset; c = min(iov->iov_len, MAXPHYS); if (!kernacc((caddr_t)kernloc, c, uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) return (EFAULT); error = uiomove((caddr_t)kernloc, (int)c, uio); continue; /* minor device 2 is EOF/RATHOLE */ case 2: if (uio->uio_rw == UIO_WRITE) uio->uio_resid = 0; return (0); /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ case 12: if (uio->uio_rw == UIO_WRITE) { c = iov->iov_len; break; } /* * On the first call, allocate and zero a page * of memory for use with /dev/zero. * * XXX on the hp300 we already know where there * is a global zeroed page, the null segment table. */ if (zeropage == NULL) { #if CLBYTES == NBPG extern caddr_t Segtabzero; zeropage = Segtabzero; #else zeropage = (caddr_t) malloc(CLBYTES, M_TEMP, M_WAITOK); bzero(zeropage, CLBYTES); #endif } c = min(iov->iov_len, CLBYTES); error = uiomove(zeropage, (int)c, uio); continue; default: return (ENXIO); } if (error) break; iov->iov_base += c; iov->iov_len -= c; uio->uio_offset += c; uio->uio_resid -= c; } return (error); } mmmap(dev, off, prot) dev_t dev; { /* * /dev/mem is the only one that makes sense through this * interface. For /dev/kmem any physaddr we return here * could be transient and hence incorrect or invalid at * a later time. /dev/null just doesn't make any sense * and /dev/zero is a hack that is handled via the default * pager in mmap(). */ if (minor(dev) != 0) return (-1); /* * Allow access only in RAM. * * XXX could be extended to allow access to IO space but must * be very careful. */ if ((unsigned)off < lowram || (unsigned)off >= 0xFFFFFFFC) return (-1); return (hp300_btop(off)); }