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 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * from: Utah $Hdr: mem.c 1.13 89/10/08$ 40 * from: @(#)mem.c 7.2 (Berkeley) 5/9/91 41 * $Id: mem.c,v 1.20 1995/11/29 10:47:18 julian Exp $ 42 */ 43 44 /* 45 * Memory special file 46 */ 47 48 #include <sys/param.h> 49 #include <sys/conf.h> 50 #include <sys/buf.h> 51 #include <sys/systm.h> 52 #include <sys/uio.h> 53 #include <sys/malloc.h> 54 #include <sys/proc.h> 55 56 #include <machine/cpu.h> 57 #include <machine/random.h> 58 #include <machine/psl.h> 59 60 #include <vm/vm.h> 61 #include <vm/vm_param.h> 62 #include <vm/lock.h> 63 #include <vm/vm_prot.h> 64 #include <vm/pmap.h> 65 66 #ifdef JREMOD 67 #include <sys/kernel.h> 68 #define CDEV_MAJOR 2 69 #endif /*JREMOD*/ 70 71 #ifdef DEVFS 72 #include <sys/devfsext.h> 73 74 static void 75 memdevfs_init(dev_t dev) 76 { 77 void * x; 78 int maj = major(dev); 79 /* path name major minor type uid gid perm*/ 80 x=devfs_add_devsw("/misc", "mem", maj, 0, DV_CHR, 0, 2, 0640); 81 x=devfs_add_devsw("/misc", "kmem", maj, 1, DV_CHR, 0, 2, 0640); 82 x=devfs_add_devsw("/misc", "null", maj, 2, DV_CHR, 0, 0, 0666); 83 x=devfs_add_devsw("/misc", "random", maj, 3, DV_CHR, 0, 0, 0666); 84 x=devfs_add_devsw("/misc", "urandom", maj, 4, DV_CHR, 0, 0, 0666); 85 x=devfs_add_devsw("/misc", "zero", maj, 12, DV_CHR, 0, 0, 0666); 86 x=devfs_add_devsw("/misc", "io", maj, 14, DV_CHR, 0, 2, 0640); 87 } 88 #endif /* DEVFS */ 89 90 extern char *ptvmmap; /* poor name! */ 91 92 int 93 mmclose(dev, flags, fmt, p) 94 dev_t dev; 95 int flags; 96 int fmt; 97 struct proc *p; 98 { 99 struct trapframe *fp; 100 101 switch (minor(dev)) { 102 case 14: 103 fp = (struct trapframe *)curproc->p_md.md_regs; 104 fp->tf_eflags &= ~PSL_IOPL; 105 break; 106 default: 107 break; 108 } 109 return(0); 110 } 111 112 int 113 mmopen(dev, flags, fmt, p) 114 dev_t dev; 115 int flags; 116 int fmt; 117 struct proc *p; 118 { 119 struct trapframe *fp; 120 121 switch (minor(dev)) { 122 case 14: 123 fp = (struct trapframe *)curproc->p_md.md_regs; 124 fp->tf_eflags |= PSL_IOPL; 125 break; 126 default: 127 break; 128 } 129 return(0); 130 } 131 132 int 133 mmrw(dev, uio, flags) 134 dev_t dev; 135 struct uio *uio; 136 int flags; 137 { 138 register int o; 139 register u_int c, v; 140 u_int poolsize; 141 register struct iovec *iov; 142 int error = 0; 143 caddr_t buf = NULL; 144 145 while (uio->uio_resid > 0 && error == 0) { 146 iov = uio->uio_iov; 147 if (iov->iov_len == 0) { 148 uio->uio_iov++; 149 uio->uio_iovcnt--; 150 if (uio->uio_iovcnt < 0) 151 panic("mmrw"); 152 continue; 153 } 154 switch (minor(dev)) { 155 156 /* minor device 0 is physical memory */ 157 case 0: 158 v = uio->uio_offset; 159 pmap_enter(kernel_pmap, (vm_offset_t)ptvmmap, v, 160 uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE, 161 TRUE); 162 o = (int)uio->uio_offset & PGOFSET; 163 c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET)); 164 c = min(c, (u_int)(NBPG - o)); 165 c = min(c, (u_int)iov->iov_len); 166 error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio); 167 pmap_remove(kernel_pmap, (vm_offset_t)ptvmmap, 168 (vm_offset_t)&ptvmmap[NBPG]); 169 continue; 170 171 /* minor device 1 is kernel memory */ 172 case 1: { 173 vm_offset_t addr, eaddr; 174 c = iov->iov_len; 175 176 /* 177 * Make sure that all of the pages are currently resident so 178 * that we don't create any zero-fill pages. 179 */ 180 addr = trunc_page(uio->uio_offset); 181 eaddr = round_page(uio->uio_offset + c); 182 for (; addr < eaddr; addr += PAGE_SIZE) 183 if (pmap_extract(kernel_pmap, addr) == 0) 184 return EFAULT; 185 186 if (!kernacc((caddr_t)(int)uio->uio_offset, c, 187 uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) 188 return(EFAULT); 189 error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio); 190 continue; 191 } 192 193 /* minor device 2 is EOF/RATHOLE */ 194 case 2: 195 if (uio->uio_rw == UIO_READ) 196 return (0); 197 c = iov->iov_len; 198 break; 199 200 /* minor device 3 (/dev/random) is source of filth on read, rathole on write */ 201 case 3: 202 if (uio->uio_rw == UIO_WRITE) { 203 c = iov->iov_len; 204 break; 205 } 206 if (buf == NULL) 207 buf = (caddr_t) 208 malloc(CLBYTES, M_TEMP, M_WAITOK); 209 c = min(iov->iov_len, CLBYTES); 210 poolsize = read_random(buf, c); 211 if (poolsize == 0) { 212 if (buf) 213 free(buf, M_TEMP); 214 return (0); 215 } 216 c = min(c, poolsize); 217 error = uiomove(buf, (int)c, uio); 218 continue; 219 220 /* minor device 4 (/dev/urandom) is source of muck on read, rathole on write */ 221 case 4: 222 if (uio->uio_rw == UIO_WRITE) { 223 c = iov->iov_len; 224 break; 225 } 226 if (buf == NULL) 227 buf = (caddr_t) 228 malloc(CLBYTES, M_TEMP, M_WAITOK); 229 c = min(iov->iov_len, CLBYTES); 230 poolsize = read_random_unlimited(buf, c); 231 c = min(c, poolsize); 232 error = uiomove(buf, (int)c, uio); 233 continue; 234 235 /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ 236 case 12: 237 if (uio->uio_rw == UIO_WRITE) { 238 c = iov->iov_len; 239 break; 240 } 241 if (buf == NULL) { 242 buf = (caddr_t) 243 malloc(CLBYTES, M_TEMP, M_WAITOK); 244 bzero(buf, CLBYTES); 245 } 246 c = min(iov->iov_len, CLBYTES); 247 error = uiomove(buf, (int)c, uio); 248 continue; 249 250 #ifdef notyet 251 /* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate 252 i/o device address bus, different than memory bus. Semantics here are 253 very different than ordinary read/write, as if iov_len is a multiple 254 an implied string move from a single port will be done. Note that lseek 255 must be used to set the port number reliably. */ 256 case 14: 257 if (iov->iov_len == 1) { 258 u_char tmp; 259 tmp = inb(uio->uio_offset); 260 error = uiomove (&tmp, iov->iov_len, uio); 261 } else { 262 if (!useracc((caddr_t)iov->iov_base, 263 iov->iov_len, uio->uio_rw)) 264 return (EFAULT); 265 insb(uio->uio_offset, iov->iov_base, 266 iov->iov_len); 267 } 268 break; 269 case 15: 270 if (iov->iov_len == sizeof (short)) { 271 u_short tmp; 272 tmp = inw(uio->uio_offset); 273 error = uiomove (&tmp, iov->iov_len, uio); 274 } else { 275 if (!useracc((caddr_t)iov->iov_base, 276 iov->iov_len, uio->uio_rw)) 277 return (EFAULT); 278 insw(uio->uio_offset, iov->iov_base, 279 iov->iov_len/ sizeof (short)); 280 } 281 break; 282 case 16: 283 if (iov->iov_len == sizeof (long)) { 284 u_long tmp; 285 tmp = inl(uio->uio_offset); 286 error = uiomove (&tmp, iov->iov_len, uio); 287 } else { 288 if (!useracc((caddr_t)iov->iov_base, 289 iov->iov_len, uio->uio_rw)) 290 return (EFAULT); 291 insl(uio->uio_offset, iov->iov_base, 292 iov->iov_len/ sizeof (long)); 293 } 294 break; 295 #endif 296 297 default: 298 return (ENXIO); 299 } 300 if (error) 301 break; 302 iov->iov_base += c; 303 iov->iov_len -= c; 304 uio->uio_offset += c; 305 uio->uio_resid -= c; 306 } 307 if (buf) 308 free(buf, M_TEMP); 309 return (error); 310 } 311 312 313 314 315 /*******************************************************\ 316 * allow user processes to MMAP some memory sections * 317 * instead of going through read/write * 318 \*******************************************************/ 319 int memmmap(dev_t dev, int offset, int nprot) 320 { 321 switch (minor(dev)) 322 { 323 324 /* minor device 0 is physical memory */ 325 case 0: 326 return i386_btop(offset); 327 328 /* minor device 1 is kernel memory */ 329 case 1: 330 return i386_btop(vtophys(offset)); 331 332 default: 333 return -1; 334 } 335 } 336 337 /* 338 * Allow userland to select which interrupts will be used in the muck 339 * gathering business. 340 */ 341 int 342 mmioctl(dev, cmd, cmdarg, flags, p) 343 dev_t dev; 344 int cmd; 345 caddr_t cmdarg; 346 int flags; 347 struct proc *p; 348 { 349 int error; 350 351 if (minor(dev) != 3 && minor(dev) != 4) 352 return (ENODEV); 353 354 if (*(u_int16_t *)cmdarg >= 16) 355 return (EINVAL); 356 357 /* Only root can do this */ 358 error = suser(p->p_ucred, &p->p_acflag); 359 if (error != 0) { 360 return (error); 361 } 362 363 switch (cmd){ 364 365 case MEM_SETIRQ: 366 interrupt_allowed |= 1 << *(u_int16_t *)cmdarg; 367 break; 368 369 case MEM_CLEARIRQ: 370 interrupt_allowed &= ~(1 << *(u_int16_t *)cmdarg); 371 break; 372 373 case MEM_RETURNIRQ: 374 *(u_int16_t *)cmdarg = interrupt_allowed; 375 break; 376 377 default: 378 return (ENOTTY); 379 } 380 return (0); 381 } 382 383 384 385 #ifdef JREMOD 386 struct cdevsw mem_cdevsw = 387 { mmopen, mmclose, mmrw, mmrw, /*2*/ 388 mmioctl, nullstop, nullreset, nodevtotty,/* memory */ 389 seltrue, memmmap, NULL }; 390 391 static mem_devsw_installed = 0; 392 393 static void mem_drvinit(void *unused) 394 { 395 dev_t dev; 396 397 if( ! mem_devsw_installed ) { 398 dev = makedev(CDEV_MAJOR,0); 399 cdevsw_add(&dev,&mem_cdevsw,NULL); 400 mem_devsw_installed = 1; 401 #ifdef DEVFS 402 memdevfs_init(dev); 403 #endif 404 } 405 } 406 407 SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL) 408 409 #endif /* JREMOD */ 410 411