1 /*- 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department, and code derived from software contributed to 9 * Berkeley by William Jolitz. 10 * 11 * %sccs.include.redist.c% 12 * 13 * from: Utah $Hdr: mem.c 1.13 89/10/08$ 14 * @(#)mem.c 7.2 (Berkeley) 05/09/91 15 */ 16 17 /* 18 * Memory special file 19 */ 20 21 #include "param.h" 22 #include "conf.h" 23 #include "buf.h" 24 #include "systm.h" 25 #include "uio.h" 26 #include "malloc.h" 27 28 #include "machine/cpu.h" 29 30 #include "vm/vm_param.h" 31 #include "vm/lock.h" 32 #include "vm/vm_statistics.h" 33 #include "vm/pmap.h" 34 #include "vm/vm_prot.h" 35 36 extern char *vmmap; /* poor name! */ 37 /*ARGSUSED*/ 38 mmrw(dev, uio, flags) 39 dev_t dev; 40 struct uio *uio; 41 int flags; 42 { 43 register int o; 44 register u_int c, v; 45 register struct iovec *iov; 46 int error = 0; 47 caddr_t zbuf = NULL; 48 49 while (uio->uio_resid > 0 && error == 0) { 50 iov = uio->uio_iov; 51 if (iov->iov_len == 0) { 52 uio->uio_iov++; 53 uio->uio_iovcnt--; 54 if (uio->uio_iovcnt < 0) 55 panic("mmrw"); 56 continue; 57 } 58 switch (minor(dev)) { 59 60 /* minor device 0 is physical memory */ 61 case 0: 62 v = uio->uio_offset; 63 pmap_enter(pmap_kernel(), vmmap, v, 64 uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE, 65 TRUE); 66 o = (int)uio->uio_offset & PGOFSET; 67 c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET)); 68 c = MIN(c, (u_int)(NBPG - o)); 69 c = MIN(c, (u_int)iov->iov_len); 70 error = uiomove((caddr_t)&vmmap[o], (int)c, uio); 71 pmap_remove(pmap_kernel(), vmmap, &vmmap[NBPG]); 72 continue; 73 74 /* minor device 1 is kernel memory */ 75 case 1: 76 c = iov->iov_len; 77 if (!kernacc((caddr_t)uio->uio_offset, c, 78 uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) 79 return(EFAULT); 80 error = uiomove((caddr_t)uio->uio_offset, (int)c, uio); 81 continue; 82 83 /* minor device 2 is EOF/RATHOLE */ 84 case 2: 85 if (uio->uio_rw == UIO_READ) 86 return (0); 87 c = iov->iov_len; 88 break; 89 90 /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ 91 case 12: 92 if (uio->uio_rw == UIO_WRITE) { 93 c = iov->iov_len; 94 break; 95 } 96 if (zbuf == NULL) { 97 zbuf = (caddr_t) 98 malloc(CLBYTES, M_TEMP, M_WAITOK); 99 bzero(zbuf, CLBYTES); 100 } 101 c = MIN(iov->iov_len, CLBYTES); 102 error = uiomove(zbuf, (int)c, uio); 103 continue; 104 105 #ifdef notyet 106 /* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate 107 i/o device address bus, different than memory bus. Semantics here are 108 very different than ordinary read/write, as if iov_len is a multiple 109 an implied string move from a single port will be done. Note that lseek 110 must be used to set the port number reliably. */ 111 case 14: 112 if (iov->iov_len == 1) { 113 u_char tmp; 114 tmp = inb(uio->uio_offset); 115 error = uiomove (&tmp, iov->iov_len, uio); 116 } else { 117 if (!useracc((caddr_t)iov->iov_base, 118 iov->iov_len, uio->uio_rw)) 119 return (EFAULT); 120 insb(uio->uio_offset, iov->iov_base, 121 iov->iov_len); 122 } 123 break; 124 case 15: 125 if (iov->iov_len == sizeof (short)) { 126 u_short tmp; 127 tmp = inw(uio->uio_offset); 128 error = uiomove (&tmp, iov->iov_len, uio); 129 } else { 130 if (!useracc((caddr_t)iov->iov_base, 131 iov->iov_len, uio->uio_rw)) 132 return (EFAULT); 133 insw(uio->uio_offset, iov->iov_base, 134 iov->iov_len/ sizeof (short)); 135 } 136 break; 137 case 16: 138 if (iov->iov_len == sizeof (long)) { 139 u_long tmp; 140 tmp = inl(uio->uio_offset); 141 error = uiomove (&tmp, iov->iov_len, uio); 142 } else { 143 if (!useracc((caddr_t)iov->iov_base, 144 iov->iov_len, uio->uio_rw)) 145 return (EFAULT); 146 insl(uio->uio_offset, iov->iov_base, 147 iov->iov_len/ sizeof (long)); 148 } 149 break; 150 #endif 151 152 default: 153 return (ENXIO); 154 } 155 if (error) 156 break; 157 iov->iov_base += c; 158 iov->iov_len -= c; 159 uio->uio_offset += c; 160 uio->uio_resid -= c; 161 } 162 if (zbuf) 163 free(zbuf, M_TEMP); 164 return (error); 165 } 166