panic() cleanup.
[minix.git] / drivers / random / main.c
blob4e383a677cc90f83837b486d01744b811978489e
1 /* This file contains the device dependent part of the drivers for the
2 * following special files:
3 * /dev/random - random number generator
4 */
6 #include "../drivers.h"
7 #include "../libdriver/driver.h"
8 #include <minix/type.h>
10 #include "assert.h"
11 #include "random.h"
13 #define NR_DEVS 1 /* number of minor devices */
14 # define RANDOM_DEV 0 /* minor device for /dev/random */
16 #define KRANDOM_PERIOD 1 /* ticks between krandom calls */
18 PRIVATE struct device m_geom[NR_DEVS]; /* base and size of each device */
19 PRIVATE int m_device; /* current device */
21 extern int errno; /* error number for PM calls */
23 FORWARD _PROTOTYPE( char *r_name, (void) );
24 FORWARD _PROTOTYPE( struct device *r_prepare, (int device) );
25 FORWARD _PROTOTYPE( int r_transfer, (int proc_nr, int opcode, u64_t position,
26 iovec_t *iov, unsigned nr_req) );
27 FORWARD _PROTOTYPE( int r_do_open, (struct driver *dp, message *m_ptr) );
28 FORWARD _PROTOTYPE( int r_ioctl, (struct driver *dp, message *m_ptr) );
29 FORWARD _PROTOTYPE( void r_geometry, (struct partition *entry) );
30 FORWARD _PROTOTYPE( void r_random, (struct driver *dp, message *m_ptr) );
31 FORWARD _PROTOTYPE( void r_updatebin, (int source, struct k_randomness_bin *rb));
33 /* Entry points to this driver. */
34 PRIVATE struct driver r_dtab = {
35 r_name, /* current device's name */
36 r_do_open, /* open or mount */
37 do_nop, /* nothing on a close */
38 r_ioctl, /* specify ram disk geometry */
39 r_prepare, /* prepare for I/O on a given minor device */
40 r_transfer, /* do the I/O */
41 nop_cleanup, /* no need to clean up */
42 r_geometry, /* device "geometry" */
43 nop_signal, /* system signals */
44 r_random, /* get randomness from kernel (alarm) */
45 nop_cancel,
46 nop_select,
47 NULL,
48 NULL
51 /* Buffer for the /dev/random number generator. */
52 #define RANDOM_BUF_SIZE 1024
53 PRIVATE char random_buf[RANDOM_BUF_SIZE];
55 /* SEF functions and variables. */
56 FORWARD _PROTOTYPE( void sef_local_startup, (void) );
57 FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
59 /*===========================================================================*
60 * main *
61 *===========================================================================*/
62 PUBLIC int main(void)
64 /* SEF local startup. */
65 sef_local_startup();
67 /* Call the generic receive loop. */
68 driver_task(&r_dtab, DRIVER_ASYN);
70 return(OK);
73 /*===========================================================================*
74 * sef_local_startup *
75 *===========================================================================*/
76 PRIVATE void sef_local_startup()
78 /* Register init callbacks. */
79 sef_setcb_init_fresh(sef_cb_init_fresh);
80 sef_setcb_init_lu(sef_cb_init_fresh);
81 sef_setcb_init_restart(sef_cb_init_fresh);
83 /* Register live update callbacks. */
84 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
85 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
87 /* Let SEF perform startup. */
88 sef_startup();
91 /*===========================================================================*
92 * sef_cb_init_fresh *
93 *===========================================================================*/
94 PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
96 /* Initialize the random driver. */
97 static struct k_randomness krandom;
98 int i, s;
100 random_init();
101 r_random(NULL, NULL); /* also set periodic timer */
103 /* Retrieve first randomness buffer with parameters. */
104 if (OK != (s=sys_getrandomness(&krandom))) {
105 printf("RANDOM: sys_getrandomness failed: %d\n", s);
106 exit(1);
109 /* Do sanity check on parameters. */
110 if(krandom.random_sources != RANDOM_SOURCES ||
111 krandom.random_elements != RANDOM_ELEMENTS) {
112 printf("random: parameters (%d, %d) don't match kernel's (%d, %d)\n",
113 RANDOM_SOURCES, RANDOM_ELEMENTS,
114 krandom.random_sources, krandom.random_elements);
115 exit(1);
118 /* Feed initial batch. */
119 for(i = 0; i < RANDOM_SOURCES; i++)
120 r_updatebin(i, &krandom.bin[i]);
122 return(OK);
125 /*===========================================================================*
126 * r_name *
127 *===========================================================================*/
128 PRIVATE char *r_name()
130 /* Return a name for the current device. */
131 static char name[] = "random";
132 return name;
135 /*===========================================================================*
136 * r_prepare *
137 *===========================================================================*/
138 PRIVATE struct device *r_prepare(device)
139 int device;
141 /* Prepare for I/O on a device: check if the minor device number is ok. */
143 if (device < 0 || device >= NR_DEVS) return(NIL_DEV);
144 m_device = device;
146 return(&m_geom[device]);
149 /*===========================================================================*
150 * r_transfer *
151 *===========================================================================*/
152 PRIVATE int r_transfer(proc_nr, opcode, position, iov, nr_req)
153 int proc_nr; /* process doing the request */
154 int opcode; /* DEV_GATHER or DEV_SCATTER */
155 u64_t position; /* offset on device to read or write */
156 iovec_t *iov; /* pointer to read or write request vector */
157 unsigned nr_req; /* length of request vector */
159 /* Read or write one the driver's minor devices. */
160 unsigned count, left, chunk;
161 vir_bytes user_vir;
162 struct device *dv;
163 int r;
164 size_t vir_offset = 0;
166 /* Get minor device number and check for /dev/null. */
167 dv = &m_geom[m_device];
169 while (nr_req > 0) {
171 /* How much to transfer and where to / from. */
172 count = iov->iov_size;
173 user_vir = iov->iov_addr;
175 switch (m_device) {
177 /* Random number generator. Character instead of block device. */
178 case RANDOM_DEV:
179 if (opcode == DEV_GATHER_S && !random_isseeded())
180 return(EAGAIN);
181 left = count;
182 while (left > 0) {
183 chunk = (left > RANDOM_BUF_SIZE) ? RANDOM_BUF_SIZE : left;
184 if (opcode == DEV_GATHER_S) {
185 random_getbytes(random_buf, chunk);
186 r= sys_safecopyto(proc_nr, user_vir, vir_offset,
187 (vir_bytes) random_buf, chunk, D);
188 if (r != OK)
190 printf(
191 "random: sys_safecopyto failed for proc %d, grant %d\n",
192 proc_nr, user_vir);
193 return r;
195 } else if (opcode == DEV_SCATTER_S) {
196 r= sys_safecopyfrom(proc_nr, user_vir, vir_offset,
197 (vir_bytes) random_buf, chunk, D);
198 if (r != OK)
200 printf(
201 "random: sys_safecopyfrom failed for proc %d, grant %d\n",
202 proc_nr, user_vir);
203 return r;
205 random_putbytes(random_buf, chunk);
207 vir_offset += chunk;
208 left -= chunk;
210 break;
212 /* Unknown (illegal) minor device. */
213 default:
214 return(EINVAL);
217 /* Book the number of bytes transferred. */
218 position= add64u(position, count);
219 if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; }
222 return(OK);
225 /*============================================================================*
226 * r_do_open *
227 *============================================================================*/
228 PRIVATE int r_do_open(dp, m_ptr)
229 struct driver *dp;
230 message *m_ptr;
232 /* Check device number on open.
234 if (r_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
236 return(OK);
239 /*===========================================================================*
240 * r_ioctl *
241 *===========================================================================*/
242 PRIVATE int r_ioctl(dp, m_ptr)
243 struct driver *dp; /* pointer to driver structure */
244 message *m_ptr; /* pointer to control message */
246 if (r_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
248 switch (m_ptr->REQUEST) {
250 default:
251 return(do_diocntl(&r_dtab, m_ptr));
253 return(OK);
256 #define UPDATE(binnumber, bp, startitem, elems) { \
257 rand_t *r; \
258 int n = elems, item = startitem;\
259 int high; \
260 assert(binnumber >= 0 && binnumber < RANDOM_SOURCES); \
261 assert(item >= 0 && item < RANDOM_ELEMENTS); \
262 if(n > 0) { \
263 high = item+n-1; \
264 assert(high >= item); \
265 assert(high >= 0 && high < RANDOM_ELEMENTS); \
266 r = &bp->r_buf[item]; \
267 random_update(binnumber, r, n); \
271 PRIVATE void r_updatebin(int source, struct k_randomness_bin *rb)
273 int r_next, r_size, r_high;
275 r_next= rb->r_next;
276 r_size= rb->r_size;
278 assert(r_next >= 0 && r_next < RANDOM_ELEMENTS);
279 assert(r_size >= 0 && r_size <= RANDOM_ELEMENTS);
281 r_high= r_next+r_size;
283 if (r_high <= RANDOM_ELEMENTS) {
284 UPDATE(source, rb, r_next, r_size);
285 } else {
286 assert(r_next < RANDOM_ELEMENTS);
287 UPDATE(source, rb, r_next, RANDOM_ELEMENTS-r_next);
288 UPDATE(source, rb, 0, r_high-RANDOM_ELEMENTS);
291 return;
294 /*============================================================================*
295 * r_random *
296 *============================================================================*/
297 PRIVATE void r_random(dp, m_ptr)
298 struct driver *dp; /* pointer to driver structure */
299 message *m_ptr; /* pointer to alarm message */
301 /* Fetch random information from the kernel to update /dev/random. */
302 int s;
303 static int bin = 0;
304 static struct k_randomness_bin krandom_bin;
305 u32_t hi, lo;
306 rand_t r;
308 bin = (bin+1) % RANDOM_SOURCES;
310 if(sys_getrandom_bin(&krandom_bin, bin) == OK)
311 r_updatebin(bin, &krandom_bin);
313 /* Add our own timing source. */
314 read_tsc(&hi, &lo);
315 r = lo;
316 random_update(RND_TIMING, &r, 1);
318 /* Schedule new alarm for next m_random call. */
319 if (OK != (s=sys_setalarm(KRANDOM_PERIOD, 0)))
320 printf("RANDOM: sys_setalarm failed: %d\n", s);
323 /*============================================================================*
324 * r_geometry *
325 *============================================================================*/
326 PRIVATE void r_geometry(struct partition *entry)
328 /* Memory devices don't have a geometry, but the outside world insists. */
329 entry->cylinders = div64u(m_geom[m_device].dv_size, SECTOR_SIZE) / (64 * 32);
330 entry->heads = 64;
331 entry->sectors = 32;