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/drivers/random/main.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 /* This file contains the device dependent part of the drivers for the
    2  * following special files:
    3  *     /dev/random      - random number generator
    4  */
    5 
    6 #include "../drivers.h"
    7 #include "../libdriver/driver.h"
    8 #include <sys/ioc_memory.h>
    9 #include "../../kernel/const.h"
   10 #include "../../kernel/config.h"
   11 #include "../../kernel/type.h"
   12 
   13 #include "assert.h"
   14 #include "random.h"
   15 
   16 #define NR_DEVS            1            /* number of minor devices */
   17 #  define RANDOM_DEV  0                 /* minor device for /dev/random */
   18 
   19 #define KRANDOM_PERIOD    1             /* ticks between krandom calls */
   20 
   21 PRIVATE struct device m_geom[NR_DEVS];  /* base and size of each device */
   22 PRIVATE int m_device;                   /* current device */
   23 
   24 extern int errno;                       /* error number for PM calls */
   25 
   26 FORWARD _PROTOTYPE( char *r_name, (void) );
   27 FORWARD _PROTOTYPE( struct device *r_prepare, (int device) );
   28 FORWARD _PROTOTYPE( int r_transfer, (int proc_nr, int opcode, off_t position,
   29                                         iovec_t *iov, unsigned nr_req) );
   30 FORWARD _PROTOTYPE( int r_do_open, (struct driver *dp, message *m_ptr) );
   31 FORWARD _PROTOTYPE( void r_init, (void) );
   32 FORWARD _PROTOTYPE( int r_ioctl, (struct driver *dp, message *m_ptr) );
   33 FORWARD _PROTOTYPE( void r_geometry, (struct partition *entry) );
   34 FORWARD _PROTOTYPE( void r_random, (struct driver *dp, message *m_ptr) );
   35 
   36 /* Entry points to this driver. */
   37 PRIVATE struct driver r_dtab = {
   38   r_name,       /* current device's name */
   39   r_do_open,    /* open or mount */
   40   do_nop,       /* nothing on a close */
   41   r_ioctl,      /* specify ram disk geometry */
   42   r_prepare,    /* prepare for I/O on a given minor device */
   43   r_transfer,   /* do the I/O */
   44   nop_cleanup,  /* no need to clean up */
   45   r_geometry,   /* device "geometry" */
   46   nop_signal,   /* system signals */
   47   r_random,     /* get randomness from kernel (alarm) */
   48   nop_cancel,
   49   nop_select,
   50   NULL,
   51   NULL
   52 };
   53 
   54 /* Buffer for the /dev/random number generator. */
   55 #define RANDOM_BUF_SIZE                 1024
   56 PRIVATE char random_buf[RANDOM_BUF_SIZE];
   57 
   58 /*===========================================================================*
   59  *                                 main                                      *
   60  *===========================================================================*/
   61 PUBLIC int main(void)
   62 {
   63   r_init();                     /* initialize the memory driver */
   64   driver_task(&r_dtab);         /* start driver's main loop */
   65   return(OK);
   66 }
   67 
   68 /*===========================================================================*
   69  *                               r_name                                      *
   70  *===========================================================================*/
   71 PRIVATE char *r_name()
   72 {
   73 /* Return a name for the current device. */
   74   static char name[] = "random";
   75   return name;  
   76 }
   77 
   78 /*===========================================================================*
   79  *                              r_prepare                                    *
   80  *===========================================================================*/
   81 PRIVATE struct device *r_prepare(device)
   82 int device;
   83 {
   84 /* Prepare for I/O on a device: check if the minor device number is ok. */
   85 
   86   if (device < 0 || device >= NR_DEVS) return(NIL_DEV);
   87   m_device = device;
   88 
   89   return(&m_geom[device]);
   90 }
   91 
   92 /*===========================================================================*
   93  *                              r_transfer                                   *
   94  *===========================================================================*/
   95 PRIVATE int r_transfer(proc_nr, opcode, position, iov, nr_req)
   96 int proc_nr;                    /* process doing the request */
   97 int opcode;                     /* DEV_GATHER or DEV_SCATTER */
   98 off_t position;                 /* offset on device to read or write */
   99 iovec_t *iov;                   /* pointer to read or write request vector */
  100 unsigned nr_req;                /* length of request vector */
  101 {
  102 /* Read or write one the driver's minor devices. */
  103   unsigned count, left, chunk;
  104   vir_bytes user_vir;
  105   struct device *dv;
  106   unsigned long dv_size;
  107 
  108   /* Get minor device number and check for /dev/null. */
  109   dv = &m_geom[m_device];
  110   dv_size = cv64ul(dv->dv_size);
  111 
  112   while (nr_req > 0) {
  113 
  114         /* How much to transfer and where to / from. */
  115         count = iov->iov_size;
  116         user_vir = iov->iov_addr;
  117 
  118         switch (m_device) {
  119 
  120         /* Random number generator. Character instead of block device. */
  121         case RANDOM_DEV:
  122             if (opcode == DEV_GATHER && !random_isseeded())
  123                     return(EAGAIN);
  124             left = count;
  125             while (left > 0) {
  126                 chunk = (left > RANDOM_BUF_SIZE) ? RANDOM_BUF_SIZE : left;
  127                 if (opcode == DEV_GATHER) {
  128                     random_getbytes(random_buf, chunk);
  129                     sys_vircopy(SELF, D, (vir_bytes) random_buf, 
  130                         proc_nr, D, user_vir, chunk);
  131                 } else if (opcode == DEV_SCATTER) {
  132                     sys_vircopy(proc_nr, D, user_vir, 
  133                         SELF, D, (vir_bytes) random_buf, chunk);
  134                         random_putbytes(random_buf, chunk);
  135                 }
  136                 user_vir += chunk;
  137                 left -= chunk;
  138             }
  139             break;
  140 
  141         /* Unknown (illegal) minor device. */
  142         default:
  143             return(EINVAL);
  144         }
  145 
  146         /* Book the number of bytes transferred. */
  147         position += count;
  148         iov->iov_addr += count;
  149         if ((iov->iov_size -= count) == 0) { iov++; nr_req--; }
  150 
  151   }
  152   return(OK);
  153 }
  154 
  155 /*============================================================================*
  156  *                              r_do_open                                     *
  157  *============================================================================*/
  158 PRIVATE int r_do_open(dp, m_ptr)
  159 struct driver *dp;
  160 message *m_ptr;
  161 {
  162 /* Check device number on open.  
  163  */
  164   if (r_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  165 
  166   return(OK);
  167 }
  168 
  169 /*===========================================================================*
  170  *                              r_init                                       *
  171  *===========================================================================*/
  172 PRIVATE void r_init()
  173 {
  174   /* Initialize this task. All minor devices are initialized one by one. */
  175   random_init();
  176   r_random(NULL, NULL);                         /* also set periodic timer */
  177 }
  178 
  179 /*===========================================================================*
  180  *                              r_ioctl                                      *
  181  *===========================================================================*/
  182 PRIVATE int r_ioctl(dp, m_ptr)
  183 struct driver *dp;                      /* pointer to driver structure */
  184 message *m_ptr;                         /* pointer to control message */
  185 {
  186   struct device *dv;
  187   if ((dv = r_prepare(m_ptr->DEVICE)) == NIL_DEV) return(ENXIO);
  188 
  189   switch (m_ptr->REQUEST) {
  190 
  191     default:
  192         return(do_diocntl(&r_dtab, m_ptr));
  193   }
  194   return(OK);
  195 }
  196 
  197 /*============================================================================*
  198  *                              r_random                                      *
  199  *============================================================================*/
  200 PRIVATE void r_random(dp, m_ptr)
  201 struct driver *dp;                      /* pointer to driver structure */
  202 message *m_ptr;                         /* pointer to alarm message */
  203 {
  204   /* Fetch random information from the kernel to update /dev/random. */
  205   int i, s, r_next, r_size, r_high;
  206   struct randomness krandom;
  207 
  208   if (OK != (s=sys_getrandomness(&krandom)))
  209         report("RANDOM", "sys_getrandomness failed", s);
  210 
  211   for (i= 0; i<RANDOM_SOURCES; i++)     
  212   {
  213         r_next= krandom.bin[i].r_next;
  214         r_size= krandom.bin[i].r_size;
  215         r_high= r_next+r_size;
  216         if (r_high <= RANDOM_ELEMENTS)
  217         {
  218                 random_update(i, &krandom.bin[i].r_buf[r_next], r_size);
  219         }
  220         else
  221         {
  222                 assert(r_next < RANDOM_ELEMENTS);
  223                 random_update(i, &krandom.bin[i].r_buf[r_next],
  224                         RANDOM_ELEMENTS-r_next);
  225                 random_update(i, &krandom.bin[i].r_buf[0],
  226                         r_high-RANDOM_ELEMENTS);
  227         }
  228   }
  229 
  230   /* Schedule new alarm for next m_random call. */
  231   if (OK != (s=sys_setalarm(KRANDOM_PERIOD, 0)))
  232         report("RANDOM", "sys_setalarm failed", s);
  233 }
  234 
  235 /*============================================================================*
  236  *                              r_geometry                                    *
  237  *============================================================================*/
  238 PRIVATE void r_geometry(entry)
  239 struct partition *entry;
  240 {
  241   /* Memory devices don't have a geometry, but the outside world insists. */
  242   entry->cylinders = div64u(m_geom[m_device].dv_size, SECTOR_SIZE) / (64 * 32);
  243   entry->heads = 64;
  244   entry->sectors = 32;
  245 }
  246 

Cache object: d73097607b75611ff18144859ddac098


[ 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.