[9] | 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 |
|
---|