The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/mem.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * $FreeBSD$
   42  */
   43 
   44 /*
   45  * Memory special file
   46  */
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/buf.h>
   51 #include <sys/conf.h>
   52 #include <sys/fcntl.h>
   53 #include <sys/filio.h>
   54 #include <sys/ioccom.h>
   55 #include <sys/kernel.h>
   56 #include <sys/malloc.h>
   57 #include <sys/memrange.h>
   58 #include <sys/proc.h>
   59 #include <sys/random.h>
   60 #include <sys/signalvar.h>
   61 #include <sys/uio.h>
   62 #include <sys/vnode.h>
   63 
   64 #include <machine/frame.h>
   65 #include <machine/psl.h>
   66 #include <machine/specialreg.h>
   67 #include <i386/isa/intr_machdep.h>
   68 
   69 #include <vm/vm.h>
   70 #include <vm/pmap.h>
   71 #include <vm/vm_extern.h>
   72 
   73 
   74 static  d_open_t        mmopen;
   75 static  d_close_t       mmclose;
   76 static  d_read_t        mmrw;
   77 static  d_ioctl_t       mmioctl;
   78 static  d_mmap_t        memmmap;
   79 static  d_poll_t        mmpoll;
   80 
   81 #define CDEV_MAJOR 2
   82 static struct cdevsw mem_cdevsw = {
   83         /* open */      mmopen,
   84         /* close */     mmclose,
   85         /* read */      mmrw,
   86         /* write */     mmrw,
   87         /* ioctl */     mmioctl,
   88         /* poll */      mmpoll,
   89         /* mmap */      memmmap,
   90         /* strategy */  nostrategy,
   91         /* name */      "mem",
   92         /* maj */       CDEV_MAJOR,
   93         /* dump */      nodump,
   94         /* psize */     nopsize,
   95         /* flags */     D_MEM,
   96         /* bmaj */      -1
   97 };
   98 
   99 static struct random_softc random_softc[16];
  100 static caddr_t  zbuf;
  101 
  102 MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors");
  103 static int mem_ioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
  104 static int random_ioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
  105 
  106 struct mem_range_softc mem_range_softc;
  107 
  108 
  109 static int
  110 mmclose(dev, flags, fmt, p)
  111         dev_t dev;
  112         int flags;
  113         int fmt;
  114         struct proc *p;
  115 {
  116         switch (minor(dev)) {
  117         case 14:
  118                 p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
  119                 break;
  120         default:
  121                 break;
  122         }
  123         return (0);
  124 }
  125 
  126 static int
  127 mmopen(dev, flags, fmt, p)
  128         dev_t dev;
  129         int flags;
  130         int fmt;
  131         struct proc *p;
  132 {
  133         int error;
  134 
  135         switch (minor(dev)) {
  136         case 0:
  137         case 1:
  138                 if ((flags & FWRITE) && securelevel > 0)
  139                         return (EPERM);
  140                 break;
  141         case 14:
  142                 error = suser(p);
  143                 if (error != 0)
  144                         return (error);
  145                 if (securelevel > 0)
  146                         return (EPERM);
  147                 p->p_md.md_regs->tf_eflags |= PSL_IOPL;
  148                 break;
  149         default:
  150                 break;
  151         }
  152         return (0);
  153 }
  154 
  155 static int
  156 mmrw(dev, uio, flags)
  157         dev_t dev;
  158         struct uio *uio;
  159         int flags;
  160 {
  161         register int o;
  162         register u_int c;
  163         u_int poolsize;
  164         register struct iovec *iov;
  165         int error = 0;
  166         caddr_t buf = NULL;
  167 
  168         while (uio->uio_resid > 0 && error == 0) {
  169                 iov = uio->uio_iov;
  170                 if (iov->iov_len == 0) {
  171                         uio->uio_iov++;
  172                         uio->uio_iovcnt--;
  173                         if (uio->uio_iovcnt < 0)
  174                                 panic("mmrw");
  175                         continue;
  176                 }
  177                 switch (minor(dev)) {
  178 
  179 /* minor device 0 is physical memory */
  180                 case 0:
  181                         pmap_kenter((vm_offset_t)ptvmmap, 
  182                             uio->uio_offset & ~PAGE_MASK);
  183                         o = (int)uio->uio_offset & PAGE_MASK;
  184                         c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK));
  185                         c = min(c, (u_int)(PAGE_SIZE - o));
  186                         c = min(c, (u_int)iov->iov_len);
  187                         error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio);
  188                         pmap_kremove((vm_offset_t)ptvmmap);
  189                         continue;
  190 
  191 /* minor device 1 is kernel memory */
  192                 case 1: {
  193                         vm_offset_t addr, eaddr;
  194                         c = iov->iov_len;
  195 
  196                         /*
  197                          * Make sure that all of the pages are currently resident so
  198                          * that we don't create any zero-fill pages.
  199                          */
  200                         addr = trunc_page(uio->uio_offset);
  201                         eaddr = round_page(uio->uio_offset + c);
  202 
  203                         if (addr < (vm_offset_t)VADDR(PTDPTDI, 0))
  204                                 return EFAULT;
  205                         for (; addr < eaddr; addr += PAGE_SIZE) 
  206                                 if (pmap_extract(kernel_pmap, addr) == 0)
  207                                         return EFAULT;
  208                         
  209                         if (!kernacc((caddr_t)(int)uio->uio_offset, c,
  210                             uio->uio_rw == UIO_READ ? 
  211                             VM_PROT_READ : VM_PROT_WRITE))
  212                                 return (EFAULT);
  213                         error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio);
  214                         continue;
  215                 }
  216 
  217 /* minor device 2 is EOF/RATHOLE */
  218                 case 2:
  219                         if (uio->uio_rw == UIO_READ)
  220                                 return (0);
  221                         c = iov->iov_len;
  222                         break;
  223 
  224 /* minor device 3 (/dev/random) is source of filth on read, rathole on write */
  225                 case 3:
  226                         if (uio->uio_rw == UIO_WRITE) {
  227                                 c = iov->iov_len;
  228                                 break;
  229                         }
  230                         if (buf == NULL)
  231                                 buf = (caddr_t)
  232                                     malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
  233                         c = min(iov->iov_len, PAGE_SIZE);
  234                         poolsize = read_random(buf, c);
  235                         if (poolsize == 0) {
  236                                 if (buf)
  237                                         free(buf, M_TEMP);
  238                                 if ((flags & IO_NDELAY) != 0)
  239                                         return (EWOULDBLOCK);
  240                                 return (0);
  241                         }
  242                         c = min(c, poolsize);
  243                         error = uiomove(buf, (int)c, uio);
  244                         continue;
  245 
  246 /* minor device 4 (/dev/urandom) is source of muck on read, rathole on write */
  247                 case 4:
  248                         if (uio->uio_rw == UIO_WRITE) {
  249                                 c = iov->iov_len;
  250                                 break;
  251                         }
  252                         if (CURSIG(curproc) != 0) {
  253                                 /*
  254                                  * Use tsleep() to get the error code right.
  255                                  * It should return immediately.
  256                                  */
  257                                 error = tsleep(&random_softc[0],
  258                                     PZERO | PCATCH, "urand", 1);
  259                                 if (error != 0 && error != EWOULDBLOCK)
  260                                         continue;
  261                         }
  262                         if (buf == NULL)
  263                                 buf = (caddr_t)
  264                                     malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
  265                         c = min(iov->iov_len, PAGE_SIZE);
  266                         poolsize = read_random_unlimited(buf, c);
  267                         c = min(c, poolsize);
  268                         error = uiomove(buf, (int)c, uio);
  269                         continue;
  270 
  271 /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
  272                 case 12:
  273                         if (uio->uio_rw == UIO_WRITE) {
  274                                 c = iov->iov_len;
  275                                 break;
  276                         }
  277                         if (zbuf == NULL) {
  278                                 zbuf = (caddr_t)
  279                                     malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
  280                                 bzero(zbuf, PAGE_SIZE);
  281                         }
  282                         c = min(iov->iov_len, PAGE_SIZE);
  283                         error = uiomove(zbuf, (int)c, uio);
  284                         continue;
  285 
  286                 default:
  287                         return (ENODEV);
  288                 }
  289                 if (error)
  290                         break;
  291                 iov->iov_base += c;
  292                 iov->iov_len -= c;
  293                 uio->uio_offset += c;
  294                 uio->uio_resid -= c;
  295         }
  296         if (buf)
  297                 free(buf, M_TEMP);
  298         return (error);
  299 }
  300 
  301 
  302 
  303 
  304 /*******************************************************\
  305 * allow user processes to MMAP some memory sections     *
  306 * instead of going through read/write                   *
  307 \*******************************************************/
  308 static int
  309 memmmap(dev_t dev, vm_offset_t offset, int nprot)
  310 {
  311         switch (minor(dev))
  312         {
  313 
  314 /* minor device 0 is physical memory */
  315         case 0:
  316                 return i386_btop(offset);
  317 
  318 /* minor device 1 is kernel memory */
  319         case 1:
  320                 return i386_btop(vtophys(offset));
  321 
  322         default:
  323                 return -1;
  324         }
  325 }
  326 
  327 static int
  328 mmioctl(dev, cmd, data, flags, p)
  329         dev_t dev;
  330         u_long cmd;
  331         caddr_t data;
  332         int flags;
  333         struct proc *p;
  334 {
  335 
  336         switch (minor(dev)) {
  337         case 0:
  338                 return mem_ioctl(dev, cmd, data, flags, p);
  339         case 3:
  340         case 4:
  341                 return random_ioctl(dev, cmd, data, flags, p);
  342         }
  343         return (ENODEV);
  344 }
  345 
  346 /*
  347  * Operations for changing memory attributes.
  348  *
  349  * This is basically just an ioctl shim for mem_range_attr_get
  350  * and mem_range_attr_set.
  351  */
  352 static int 
  353 mem_ioctl(dev, cmd, data, flags, p)
  354         dev_t dev;
  355         u_long cmd;
  356         caddr_t data;
  357         int flags;
  358         struct proc *p;
  359 {
  360         int nd, error = 0;
  361         struct mem_range_op *mo = (struct mem_range_op *)data;
  362         struct mem_range_desc *md;
  363         
  364         /* is this for us? */
  365         if ((cmd != MEMRANGE_GET) &&
  366             (cmd != MEMRANGE_SET))
  367                 return (ENOTTY);
  368 
  369         /* any chance we can handle this? */
  370         if (mem_range_softc.mr_op == NULL)
  371                 return (EOPNOTSUPP);
  372 
  373         /* do we have any descriptors? */
  374         if (mem_range_softc.mr_ndesc == 0)
  375                 return (ENXIO);
  376 
  377         switch (cmd) {
  378         case MEMRANGE_GET:
  379                 nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc);
  380                 if (nd > 0) {
  381                         md = (struct mem_range_desc *)
  382                                 malloc(nd * sizeof(struct mem_range_desc),
  383                                        M_MEMDESC, M_WAITOK);
  384                         error = mem_range_attr_get(md, &nd);
  385                         if (!error)
  386                                 error = copyout(md, mo->mo_desc, 
  387                                         nd * sizeof(struct mem_range_desc));
  388                         free(md, M_MEMDESC);
  389                 } else {
  390                         nd = mem_range_softc.mr_ndesc;
  391                 }
  392                 mo->mo_arg[0] = nd;
  393                 break;
  394                 
  395         case MEMRANGE_SET:
  396                 md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc),
  397                                                     M_MEMDESC, M_WAITOK);
  398                 error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc));
  399                 /* clamp description string */
  400                 md->mr_owner[sizeof(md->mr_owner) - 1] = 0;
  401                 if (error == 0)
  402                         error = mem_range_attr_set(md, &mo->mo_arg[0]);
  403                 free(md, M_MEMDESC);
  404                 break;
  405         }
  406         return (error);
  407 }
  408 
  409 /*
  410  * Implementation-neutral, kernel-callable functions for manipulating
  411  * memory range attributes.
  412  */
  413 int
  414 mem_range_attr_get(mrd, arg)
  415         struct mem_range_desc *mrd;
  416         int *arg;
  417 {
  418         /* can we handle this? */
  419         if (mem_range_softc.mr_op == NULL)
  420                 return (EOPNOTSUPP);
  421 
  422         if (*arg == 0) {
  423                 *arg = mem_range_softc.mr_ndesc;
  424         } else {
  425                 bcopy(mem_range_softc.mr_desc, mrd, (*arg) * sizeof(struct mem_range_desc));
  426         }
  427         return (0);
  428 }
  429 
  430 int
  431 mem_range_attr_set(mrd, arg)
  432         struct mem_range_desc *mrd;
  433         int *arg;
  434 {
  435         /* can we handle this? */
  436         if (mem_range_softc.mr_op == NULL)
  437                 return (EOPNOTSUPP);
  438 
  439         return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg));
  440 }
  441 
  442 #ifdef SMP
  443 void
  444 mem_range_AP_init(void)
  445 {
  446         if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP)
  447                 return (mem_range_softc.mr_op->initAP(&mem_range_softc));
  448 }
  449 #endif
  450 
  451 static int 
  452 random_ioctl(dev, cmd, data, flags, p)
  453         dev_t dev;
  454         u_long cmd;
  455         caddr_t data;
  456         int flags;
  457         struct proc *p;
  458 {
  459         static intrmask_t interrupt_allowed;
  460         intrmask_t interrupt_mask;
  461         int error, intr;
  462         struct random_softc *sc;
  463         
  464         /*
  465          * We're the random or urandom device.  The only ioctls are for
  466          * selecting and inspecting which interrupts are used in the muck
  467          * gathering business and the fcntl() stuff.
  468          */
  469         if (cmd != MEM_SETIRQ && cmd != MEM_CLEARIRQ && cmd != MEM_RETURNIRQ
  470                 && cmd != FIONBIO && cmd != FIOASYNC)
  471                 return (ENOTTY);
  472 
  473         /*
  474          * XXX the data is 16-bit due to a historical botch, so we use
  475          * magic 16's instead of ICU_LEN and can't support 24 interrupts
  476          * under SMP.
  477          * Even inspecting the state is privileged, since it gives a hint
  478          * about how easily the randomness might be guessed.
  479          */
  480         intr = *(int16_t *)data;
  481         interrupt_mask = 1 << intr;
  482         sc = &random_softc[intr];
  483         switch (cmd) {
  484         /* Really handled in upper layer */
  485         case FIOASYNC:
  486         case FIONBIO:
  487                 break;
  488         case MEM_SETIRQ:
  489                 error = suser(p);
  490                 if (error != 0)
  491                         return (error);
  492                 if (intr < 0 || intr >= 16)
  493                         return (EINVAL);
  494                 if (interrupt_allowed & interrupt_mask)
  495                         break;
  496                 interrupt_allowed |= interrupt_mask;
  497                 sc->sc_intr = intr;
  498                 disable_intr();
  499                 sc->sc_handler = intr_handler[intr];
  500                 intr_handler[intr] = add_interrupt_randomness;
  501                 sc->sc_arg = intr_unit[intr];
  502                 intr_unit[intr] = sc;
  503                 enable_intr();
  504                 break;
  505         case MEM_CLEARIRQ:
  506                 error = suser(p);
  507                 if (error != 0)
  508                         return (error);
  509                 if (intr < 0 || intr >= 16)
  510                         return (EINVAL);
  511                 if (!(interrupt_allowed & interrupt_mask))
  512                         break;
  513                 interrupt_allowed &= ~interrupt_mask;
  514                 disable_intr();
  515                 intr_handler[intr] = sc->sc_handler;
  516                 intr_unit[intr] = sc->sc_arg;
  517                 enable_intr();
  518                 break;
  519         case MEM_RETURNIRQ:
  520                 error = suser(p);
  521                 if (error != 0)
  522                         return (error);
  523                 *(u_int16_t *)data = interrupt_allowed;
  524                 break;
  525         }
  526         return (0);
  527 }
  528 
  529 int
  530 mmpoll(dev, events, p)
  531         dev_t dev;
  532         int events;
  533         struct proc *p;
  534 {
  535         switch (minor(dev)) {
  536         case 3:         /* /dev/random */
  537                 return random_poll(dev, events, p);
  538         case 4:         /* /dev/urandom */
  539         default:
  540                 return seltrue(dev, events, p);
  541         }
  542 }
  543 
  544 int
  545 iszerodev(dev)
  546         dev_t dev;
  547 {
  548         return ((major(dev) == mem_cdevsw.d_maj)
  549           && minor(dev) == 12);
  550 }
  551 
  552 static void
  553 mem_drvinit(void *unused)
  554 {
  555 
  556         /* Initialise memory range handling */
  557         if (mem_range_softc.mr_op != NULL)
  558                 mem_range_softc.mr_op->init(&mem_range_softc);
  559 
  560         make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM, 0640, "mem");
  561         make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM, 0640, "kmem");
  562         make_dev(&mem_cdevsw, 2, UID_ROOT, GID_WHEEL, 0666, "null");
  563         make_dev(&mem_cdevsw, 3, UID_ROOT, GID_WHEEL, 0644, "random");
  564         make_dev(&mem_cdevsw, 4, UID_ROOT, GID_WHEEL, 0644, "urandom");
  565         make_dev(&mem_cdevsw, 12, UID_ROOT, GID_WHEEL, 0666, "zero");
  566         make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL, 0600, "io");
  567 }
  568 
  569 SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL)
  570 

Cache object: c4a60d56a7c2d714f72c9f40a0a32532


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.