main.c

Go to the documentation of this file.
00001 /* This file contains the device dependent part of the drivers for the
00002  * following special files:
00003  *     /dev/random      - random number generator
00004  */
00005 
00006 #include "../drivers.h"
00007 #include "../libdriver/driver.h"
00008 #include <sys/ioc_memory.h>
00009 #include "../../kernel/const.h"
00010 #include "../../kernel/config.h"
00011 #include "../../kernel/type.h"
00012 
00013 #include "assert.h"
00014 #include "random.h"
00015 
00016 #define NR_DEVS            1            /* number of minor devices */
00017 #  define RANDOM_DEV  0                 /* minor device for /dev/random */
00018 
00019 #define KRANDOM_PERIOD    1             /* ticks between krandom calls */
00020 
00021 PRIVATE struct device m_geom[NR_DEVS];  /* base and size of each device */
00022 PRIVATE int m_device;                   /* current device */
00023 
00024 extern int errno;                       /* error number for PM calls */
00025 
00026 FORWARD _PROTOTYPE( char *r_name, (void) );
00027 FORWARD _PROTOTYPE( struct device *r_prepare, (int device) );
00028 FORWARD _PROTOTYPE( int r_transfer, (int proc_nr, int opcode, off_t position,
00029                                         iovec_t *iov, unsigned nr_req) );
00030 FORWARD _PROTOTYPE( int r_do_open, (struct driver *dp, message *m_ptr) );
00031 FORWARD _PROTOTYPE( void r_init, (void) );
00032 FORWARD _PROTOTYPE( int r_ioctl, (struct driver *dp, message *m_ptr) );
00033 FORWARD _PROTOTYPE( void r_geometry, (struct partition *entry) );
00034 FORWARD _PROTOTYPE( void r_random, (struct driver *dp, message *m_ptr) );
00035 
00036 /* Entry points to this driver. */
00037 PRIVATE struct driver r_dtab = {
00038   r_name,       /* current device's name */
00039   r_do_open,    /* open or mount */
00040   do_nop,       /* nothing on a close */
00041   r_ioctl,      /* specify ram disk geometry */
00042   r_prepare,    /* prepare for I/O on a given minor device */
00043   r_transfer,   /* do the I/O */
00044   nop_cleanup,  /* no need to clean up */
00045   r_geometry,   /* device "geometry" */
00046   nop_signal,   /* system signals */
00047   r_random,     /* get randomness from kernel (alarm) */
00048   nop_cancel,
00049   nop_select,
00050   NULL,
00051   NULL
00052 };
00053 
00054 /* Buffer for the /dev/random number generator. */
00055 #define RANDOM_BUF_SIZE                 1024
00056 PRIVATE char random_buf[RANDOM_BUF_SIZE];
00057 
00058 /*===========================================================================*
00059  *                                 main                                      *
00060  *===========================================================================*/
00061 PUBLIC int main(void)
00062 {
00063   r_init();                     /* initialize the memory driver */
00064   driver_task(&r_dtab);         /* start driver's main loop */
00065   return(OK);
00066 }
00067 
00068 /*===========================================================================*
00069  *                               r_name                                      *
00070  *===========================================================================*/
00071 PRIVATE char *r_name()
00072 {
00073 /* Return a name for the current device. */
00074   static char name[] = "random";
00075   return name;  
00076 }
00077 
00078 /*===========================================================================*
00079  *                              r_prepare                                    *
00080  *===========================================================================*/
00081 PRIVATE struct device *r_prepare(device)
00082 int device;
00083 {
00084 /* Prepare for I/O on a device: check if the minor device number is ok. */
00085 
00086   if (device < 0 || device >= NR_DEVS) return(NIL_DEV);
00087   m_device = device;
00088 
00089   return(&m_geom[device]);
00090 }
00091 
00092 /*===========================================================================*
00093  *                              r_transfer                                   *
00094  *===========================================================================*/
00095 PRIVATE int r_transfer(proc_nr, opcode, position, iov, nr_req)
00096 int proc_nr;                    /* process doing the request */
00097 int opcode;                     /* DEV_GATHER or DEV_SCATTER */
00098 off_t position;                 /* offset on device to read or write */
00099 iovec_t *iov;                   /* pointer to read or write request vector */
00100 unsigned nr_req;                /* length of request vector */
00101 {
00102 /* Read or write one the driver's minor devices. */
00103   unsigned count, left, chunk;
00104   vir_bytes user_vir;
00105   struct device *dv;
00106   unsigned long dv_size;
00107 
00108   /* Get minor device number and check for /dev/null. */
00109   dv = &m_geom[m_device];
00110   dv_size = cv64ul(dv->dv_size);
00111 
00112   while (nr_req > 0) {
00113 
00114         /* How much to transfer and where to / from. */
00115         count = iov->iov_size;
00116         user_vir = iov->iov_addr;
00117 
00118         switch (m_device) {
00119 
00120         /* Random number generator. Character instead of block device. */
00121         case RANDOM_DEV:
00122             if (opcode == DEV_GATHER && !random_isseeded())
00123                     return(EAGAIN);
00124             left = count;
00125             while (left > 0) {
00126                 chunk = (left > RANDOM_BUF_SIZE) ? RANDOM_BUF_SIZE : left;
00127                 if (opcode == DEV_GATHER) {
00128                     random_getbytes(random_buf, chunk);
00129                     sys_vircopy(SELF, D, (vir_bytes) random_buf, 
00130                         proc_nr, D, user_vir, chunk);
00131                 } else if (opcode == DEV_SCATTER) {
00132                     sys_vircopy(proc_nr, D, user_vir, 
00133                         SELF, D, (vir_bytes) random_buf, chunk);
00134                         random_putbytes(random_buf, chunk);
00135                 }
00136                 user_vir += chunk;
00137                 left -= chunk;
00138             }
00139             break;
00140 
00141         /* Unknown (illegal) minor device. */
00142         default:
00143             return(EINVAL);
00144         }
00145 
00146         /* Book the number of bytes transferred. */
00147         position += count;
00148         iov->iov_addr += count;
00149         if ((iov->iov_size -= count) == 0) { iov++; nr_req--; }
00150 
00151   }
00152   return(OK);
00153 }
00154 
00155 /*============================================================================*
00156  *                              r_do_open                                     *
00157  *============================================================================*/
00158 PRIVATE int r_do_open(dp, m_ptr)
00159 struct driver *dp;
00160 message *m_ptr;
00161 {
00162 /* Check device number on open.  
00163  */
00164   if (r_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
00165 
00166   return(OK);
00167 }
00168 
00169 /*===========================================================================*
00170  *                              r_init                                       *
00171  *===========================================================================*/
00172 PRIVATE void r_init()
00173 {
00174   /* Initialize this task. All minor devices are initialized one by one. */
00175   random_init();
00176   r_random(NULL, NULL);                         /* also set periodic timer */
00177 }
00178 
00179 /*===========================================================================*
00180  *                              r_ioctl                                      *
00181  *===========================================================================*/
00182 PRIVATE int r_ioctl(dp, m_ptr)
00183 struct driver *dp;                      /* pointer to driver structure */
00184 message *m_ptr;                         /* pointer to control message */
00185 {
00186   struct device *dv;
00187   if ((dv = r_prepare(m_ptr->DEVICE)) == NIL_DEV) return(ENXIO);
00188 
00189   switch (m_ptr->REQUEST) {
00190 
00191     default:
00192         return(do_diocntl(&r_dtab, m_ptr));
00193   }
00194   return(OK);
00195 }
00196 
00197 /*============================================================================*
00198  *                              r_random                                      *
00199  *============================================================================*/
00200 PRIVATE void r_random(dp, m_ptr)
00201 struct driver *dp;                      /* pointer to driver structure */
00202 message *m_ptr;                         /* pointer to alarm message */
00203 {
00204   /* Fetch random information from the kernel to update /dev/random. */
00205   int i, s, r_next, r_size, r_high;
00206   struct randomness krandom;
00207 
00208   if (OK != (s=sys_getrandomness(&krandom)))
00209         report("RANDOM", "sys_getrandomness failed", s);
00210 
00211   for (i= 0; i<RANDOM_SOURCES; i++)     
00212   {
00213         r_next= krandom.bin[i].r_next;
00214         r_size= krandom.bin[i].r_size;
00215         r_high= r_next+r_size;
00216         if (r_high <= RANDOM_ELEMENTS)
00217         {
00218                 random_update(i, &krandom.bin[i].r_buf[r_next], r_size);
00219         }
00220         else
00221         {
00222                 assert(r_next < RANDOM_ELEMENTS);
00223                 random_update(i, &krandom.bin[i].r_buf[r_next],
00224                         RANDOM_ELEMENTS-r_next);
00225                 random_update(i, &krandom.bin[i].r_buf[0],
00226                         r_high-RANDOM_ELEMENTS);
00227         }
00228   }
00229 
00230   /* Schedule new alarm for next m_random call. */
00231   if (OK != (s=sys_setalarm(KRANDOM_PERIOD, 0)))
00232         report("RANDOM", "sys_setalarm failed", s);
00233 }
00234 
00235 /*============================================================================*
00236  *                              r_geometry                                    *
00237  *============================================================================*/
00238 PRIVATE void r_geometry(entry)
00239 struct partition *entry;
00240 {
00241   /* Memory devices don't have a geometry, but the outside world insists. */
00242   entry->cylinders = div64u(m_geom[m_device].dv_size, SECTOR_SIZE) / (64 * 32);
00243   entry->heads = 64;
00244   entry->sectors = 32;
00245 }
00246 

Generated on Fri Apr 14 22:56:40 2006 for minix by  doxygen 1.4.6