1*433d6423SLionel Sambuc /* This file contains the device dependent part of the drivers for the
2*433d6423SLionel Sambuc * following special files:
3*433d6423SLionel Sambuc * /dev/random - random number generator
4*433d6423SLionel Sambuc */
5*433d6423SLionel Sambuc
6*433d6423SLionel Sambuc #include <minix/drivers.h>
7*433d6423SLionel Sambuc #include <minix/chardriver.h>
8*433d6423SLionel Sambuc #include <minix/type.h>
9*433d6423SLionel Sambuc
10*433d6423SLionel Sambuc #include "assert.h"
11*433d6423SLionel Sambuc #include "random.h"
12*433d6423SLionel Sambuc
13*433d6423SLionel Sambuc #define NR_DEVS 1 /* number of minor devices */
14*433d6423SLionel Sambuc # define RANDOM_DEV 0 /* minor device for /dev/random */
15*433d6423SLionel Sambuc
16*433d6423SLionel Sambuc #define KRANDOM_PERIOD 1 /* ticks between krandom calls */
17*433d6423SLionel Sambuc
18*433d6423SLionel Sambuc static struct device m_geom[NR_DEVS]; /* base and size of each device */
19*433d6423SLionel Sambuc static dev_t m_device; /* current device */
20*433d6423SLionel Sambuc
21*433d6423SLionel Sambuc extern int errno; /* error number for PM calls */
22*433d6423SLionel Sambuc
23*433d6423SLionel Sambuc static struct device *r_prepare(dev_t device);
24*433d6423SLionel Sambuc static ssize_t r_read(devminor_t minor, u64_t position, endpoint_t endpt,
25*433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
26*433d6423SLionel Sambuc static ssize_t r_write(devminor_t minor, u64_t position, endpoint_t endpt,
27*433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
28*433d6423SLionel Sambuc static int r_open(devminor_t minor, int access, endpoint_t user_endpt);
29*433d6423SLionel Sambuc static void r_random(clock_t stamp);
30*433d6423SLionel Sambuc static void r_updatebin(int source, struct k_randomness_bin *rb);
31*433d6423SLionel Sambuc static int r_select(devminor_t, unsigned int, endpoint_t);
32*433d6423SLionel Sambuc
33*433d6423SLionel Sambuc /* Entry points to this driver. */
34*433d6423SLionel Sambuc static struct chardriver r_dtab = {
35*433d6423SLionel Sambuc .cdr_open = r_open, /* open device */
36*433d6423SLionel Sambuc .cdr_read = r_read, /* read from device */
37*433d6423SLionel Sambuc .cdr_write = r_write, /* write to device (seeding it) */
38*433d6423SLionel Sambuc .cdr_select = r_select, /* select hook */
39*433d6423SLionel Sambuc .cdr_alarm = r_random /* get randomness from kernel (alarm) */
40*433d6423SLionel Sambuc };
41*433d6423SLionel Sambuc
42*433d6423SLionel Sambuc /* select requestor */
43*433d6423SLionel Sambuc static endpoint_t random_select = NONE;
44*433d6423SLionel Sambuc
45*433d6423SLionel Sambuc /* Buffer for the /dev/random number generator. */
46*433d6423SLionel Sambuc #define RANDOM_BUF_SIZE 1024
47*433d6423SLionel Sambuc static char random_buf[RANDOM_BUF_SIZE];
48*433d6423SLionel Sambuc
49*433d6423SLionel Sambuc /* SEF functions and variables. */
50*433d6423SLionel Sambuc static void sef_local_startup(void);
51*433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *info);
52*433d6423SLionel Sambuc
53*433d6423SLionel Sambuc /*===========================================================================*
54*433d6423SLionel Sambuc * main *
55*433d6423SLionel Sambuc *===========================================================================*/
main(void)56*433d6423SLionel Sambuc int main(void)
57*433d6423SLionel Sambuc {
58*433d6423SLionel Sambuc /* SEF local startup. */
59*433d6423SLionel Sambuc sef_local_startup();
60*433d6423SLionel Sambuc
61*433d6423SLionel Sambuc /* Call the generic receive loop. */
62*433d6423SLionel Sambuc chardriver_task(&r_dtab);
63*433d6423SLionel Sambuc
64*433d6423SLionel Sambuc return(OK);
65*433d6423SLionel Sambuc }
66*433d6423SLionel Sambuc
67*433d6423SLionel Sambuc /*===========================================================================*
68*433d6423SLionel Sambuc * sef_local_startup *
69*433d6423SLionel Sambuc *===========================================================================*/
sef_local_startup()70*433d6423SLionel Sambuc static void sef_local_startup()
71*433d6423SLionel Sambuc {
72*433d6423SLionel Sambuc /* Register init callbacks. */
73*433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init_fresh);
74*433d6423SLionel Sambuc sef_setcb_init_restart(sef_cb_init_fresh);
75*433d6423SLionel Sambuc
76*433d6423SLionel Sambuc /* Let SEF perform startup. */
77*433d6423SLionel Sambuc sef_startup();
78*433d6423SLionel Sambuc }
79*433d6423SLionel Sambuc
80*433d6423SLionel Sambuc /*===========================================================================*
81*433d6423SLionel Sambuc * sef_cb_init_fresh *
82*433d6423SLionel Sambuc *===========================================================================*/
sef_cb_init_fresh(int UNUSED (type),sef_init_info_t * UNUSED (info))83*433d6423SLionel Sambuc static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
84*433d6423SLionel Sambuc {
85*433d6423SLionel Sambuc /* Initialize the random driver. */
86*433d6423SLionel Sambuc static struct k_randomness krandom;
87*433d6423SLionel Sambuc int i, s;
88*433d6423SLionel Sambuc
89*433d6423SLionel Sambuc random_init();
90*433d6423SLionel Sambuc r_random(0); /* also set periodic timer */
91*433d6423SLionel Sambuc
92*433d6423SLionel Sambuc /* Retrieve first randomness buffer with parameters. */
93*433d6423SLionel Sambuc if (OK != (s=sys_getrandomness(&krandom))) {
94*433d6423SLionel Sambuc printf("RANDOM: sys_getrandomness failed: %d\n", s);
95*433d6423SLionel Sambuc exit(1);
96*433d6423SLionel Sambuc }
97*433d6423SLionel Sambuc
98*433d6423SLionel Sambuc /* Do sanity check on parameters. */
99*433d6423SLionel Sambuc if(krandom.random_sources != RANDOM_SOURCES ||
100*433d6423SLionel Sambuc krandom.random_elements != RANDOM_ELEMENTS) {
101*433d6423SLionel Sambuc printf("random: parameters (%d, %d) don't match kernel's (%d, %d)\n",
102*433d6423SLionel Sambuc RANDOM_SOURCES, RANDOM_ELEMENTS,
103*433d6423SLionel Sambuc krandom.random_sources, krandom.random_elements);
104*433d6423SLionel Sambuc exit(1);
105*433d6423SLionel Sambuc }
106*433d6423SLionel Sambuc
107*433d6423SLionel Sambuc /* Feed initial batch. */
108*433d6423SLionel Sambuc for(i = 0; i < RANDOM_SOURCES; i++)
109*433d6423SLionel Sambuc r_updatebin(i, &krandom.bin[i]);
110*433d6423SLionel Sambuc
111*433d6423SLionel Sambuc /* Announce we are up! */
112*433d6423SLionel Sambuc chardriver_announce();
113*433d6423SLionel Sambuc
114*433d6423SLionel Sambuc return(OK);
115*433d6423SLionel Sambuc }
116*433d6423SLionel Sambuc
117*433d6423SLionel Sambuc /*===========================================================================*
118*433d6423SLionel Sambuc * r_read *
119*433d6423SLionel Sambuc *===========================================================================*/
r_read(devminor_t minor,u64_t UNUSED (position),endpoint_t endpt,cp_grant_id_t grant,size_t size,int UNUSED (flags),cdev_id_t UNUSED (id))120*433d6423SLionel Sambuc static ssize_t r_read(devminor_t minor, u64_t UNUSED(position),
121*433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
122*433d6423SLionel Sambuc cdev_id_t UNUSED(id))
123*433d6423SLionel Sambuc {
124*433d6423SLionel Sambuc /* Read from one of the driver's minor devices. */
125*433d6423SLionel Sambuc size_t offset, chunk;
126*433d6423SLionel Sambuc int r;
127*433d6423SLionel Sambuc
128*433d6423SLionel Sambuc if (minor != RANDOM_DEV) return(EIO);
129*433d6423SLionel Sambuc
130*433d6423SLionel Sambuc if (!random_isseeded()) return(EAGAIN);
131*433d6423SLionel Sambuc
132*433d6423SLionel Sambuc for (offset = 0; offset < size; offset += chunk) {
133*433d6423SLionel Sambuc chunk = MIN(size - offset, RANDOM_BUF_SIZE);
134*433d6423SLionel Sambuc random_getbytes(random_buf, chunk);
135*433d6423SLionel Sambuc r = sys_safecopyto(endpt, grant, offset, (vir_bytes)random_buf, chunk);
136*433d6423SLionel Sambuc if (r != OK) {
137*433d6423SLionel Sambuc printf("random: sys_safecopyto failed for proc %d, grant %d\n",
138*433d6423SLionel Sambuc endpt, grant);
139*433d6423SLionel Sambuc return r;
140*433d6423SLionel Sambuc }
141*433d6423SLionel Sambuc }
142*433d6423SLionel Sambuc
143*433d6423SLionel Sambuc return size;
144*433d6423SLionel Sambuc }
145*433d6423SLionel Sambuc
146*433d6423SLionel Sambuc /*===========================================================================*
147*433d6423SLionel Sambuc * r_write *
148*433d6423SLionel Sambuc *===========================================================================*/
r_write(devminor_t minor,u64_t UNUSED (position),endpoint_t endpt,cp_grant_id_t grant,size_t size,int UNUSED (flags),cdev_id_t UNUSED (id))149*433d6423SLionel Sambuc static ssize_t r_write(devminor_t minor, u64_t UNUSED(position),
150*433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
151*433d6423SLionel Sambuc cdev_id_t UNUSED(id))
152*433d6423SLionel Sambuc {
153*433d6423SLionel Sambuc /* Write to one of the driver's minor devices. */
154*433d6423SLionel Sambuc size_t offset, chunk;
155*433d6423SLionel Sambuc int r;
156*433d6423SLionel Sambuc
157*433d6423SLionel Sambuc if (minor != RANDOM_DEV) return(EIO);
158*433d6423SLionel Sambuc
159*433d6423SLionel Sambuc for (offset = 0; offset < size; offset += chunk) {
160*433d6423SLionel Sambuc chunk = MIN(size - offset, RANDOM_BUF_SIZE);
161*433d6423SLionel Sambuc r = sys_safecopyfrom(endpt, grant, offset, (vir_bytes)random_buf,
162*433d6423SLionel Sambuc chunk);
163*433d6423SLionel Sambuc if (r != OK) {
164*433d6423SLionel Sambuc printf("random: sys_safecopyfrom failed for proc %d,"
165*433d6423SLionel Sambuc " grant %d\n", endpt, grant);
166*433d6423SLionel Sambuc return r;
167*433d6423SLionel Sambuc }
168*433d6423SLionel Sambuc random_putbytes(random_buf, chunk);
169*433d6423SLionel Sambuc }
170*433d6423SLionel Sambuc
171*433d6423SLionel Sambuc return size;
172*433d6423SLionel Sambuc }
173*433d6423SLionel Sambuc
174*433d6423SLionel Sambuc /*===========================================================================*
175*433d6423SLionel Sambuc * r_open *
176*433d6423SLionel Sambuc *===========================================================================*/
r_open(devminor_t minor,int access,endpoint_t UNUSED (user_endpt))177*433d6423SLionel Sambuc static int r_open(devminor_t minor, int access, endpoint_t UNUSED(user_endpt))
178*433d6423SLionel Sambuc {
179*433d6423SLionel Sambuc /* Check device number on open.
180*433d6423SLionel Sambuc */
181*433d6423SLionel Sambuc
182*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS) return(ENXIO);
183*433d6423SLionel Sambuc
184*433d6423SLionel Sambuc return(OK);
185*433d6423SLionel Sambuc }
186*433d6423SLionel Sambuc
187*433d6423SLionel Sambuc #define UPDATE(binnumber, bp, startitem, elems) { \
188*433d6423SLionel Sambuc rand_t *r; \
189*433d6423SLionel Sambuc int n = elems, item = startitem;\
190*433d6423SLionel Sambuc int high; \
191*433d6423SLionel Sambuc assert(binnumber >= 0 && binnumber < RANDOM_SOURCES); \
192*433d6423SLionel Sambuc assert(item >= 0 && item < RANDOM_ELEMENTS); \
193*433d6423SLionel Sambuc if(n > 0) { \
194*433d6423SLionel Sambuc high = item+n-1; \
195*433d6423SLionel Sambuc assert(high >= item); \
196*433d6423SLionel Sambuc assert(high >= 0 && high < RANDOM_ELEMENTS); \
197*433d6423SLionel Sambuc r = &bp->r_buf[item]; \
198*433d6423SLionel Sambuc random_update(binnumber, r, n); \
199*433d6423SLionel Sambuc } \
200*433d6423SLionel Sambuc }
201*433d6423SLionel Sambuc
202*433d6423SLionel Sambuc /*===========================================================================*
203*433d6423SLionel Sambuc * r_updatebin *
204*433d6423SLionel Sambuc *===========================================================================*/
r_updatebin(int source,struct k_randomness_bin * rb)205*433d6423SLionel Sambuc static void r_updatebin(int source, struct k_randomness_bin *rb)
206*433d6423SLionel Sambuc {
207*433d6423SLionel Sambuc int r_next, r_size, r_high;
208*433d6423SLionel Sambuc
209*433d6423SLionel Sambuc r_next= rb->r_next;
210*433d6423SLionel Sambuc r_size= rb->r_size;
211*433d6423SLionel Sambuc
212*433d6423SLionel Sambuc assert(r_next >= 0 && r_next < RANDOM_ELEMENTS);
213*433d6423SLionel Sambuc assert(r_size >= 0 && r_size <= RANDOM_ELEMENTS);
214*433d6423SLionel Sambuc
215*433d6423SLionel Sambuc r_high= r_next+r_size;
216*433d6423SLionel Sambuc
217*433d6423SLionel Sambuc if (r_high <= RANDOM_ELEMENTS) {
218*433d6423SLionel Sambuc UPDATE(source, rb, r_next, r_size);
219*433d6423SLionel Sambuc } else {
220*433d6423SLionel Sambuc assert(r_next < RANDOM_ELEMENTS);
221*433d6423SLionel Sambuc UPDATE(source, rb, r_next, RANDOM_ELEMENTS-r_next);
222*433d6423SLionel Sambuc UPDATE(source, rb, 0, r_high-RANDOM_ELEMENTS);
223*433d6423SLionel Sambuc }
224*433d6423SLionel Sambuc
225*433d6423SLionel Sambuc return;
226*433d6423SLionel Sambuc }
227*433d6423SLionel Sambuc
228*433d6423SLionel Sambuc /*===========================================================================*
229*433d6423SLionel Sambuc * r_random *
230*433d6423SLionel Sambuc *===========================================================================*/
r_random(clock_t UNUSED (stamp))231*433d6423SLionel Sambuc static void r_random(clock_t UNUSED(stamp))
232*433d6423SLionel Sambuc {
233*433d6423SLionel Sambuc /* Fetch random information from the kernel to update /dev/random. */
234*433d6423SLionel Sambuc int s;
235*433d6423SLionel Sambuc static int bin = 0;
236*433d6423SLionel Sambuc static struct k_randomness_bin krandom_bin;
237*433d6423SLionel Sambuc u32_t hi, lo;
238*433d6423SLionel Sambuc rand_t r;
239*433d6423SLionel Sambuc int nextperiod = random_isseeded() ? KRANDOM_PERIOD*500 : KRANDOM_PERIOD;
240*433d6423SLionel Sambuc
241*433d6423SLionel Sambuc bin = (bin+1) % RANDOM_SOURCES;
242*433d6423SLionel Sambuc
243*433d6423SLionel Sambuc if(sys_getrandom_bin(&krandom_bin, bin) == OK)
244*433d6423SLionel Sambuc r_updatebin(bin, &krandom_bin);
245*433d6423SLionel Sambuc
246*433d6423SLionel Sambuc /* Add our own timing source. */
247*433d6423SLionel Sambuc read_tsc(&hi, &lo);
248*433d6423SLionel Sambuc r = lo;
249*433d6423SLionel Sambuc random_update(RND_TIMING, &r, 1);
250*433d6423SLionel Sambuc
251*433d6423SLionel Sambuc /* Schedule new alarm for next m_random call. */
252*433d6423SLionel Sambuc if (OK != (s=sys_setalarm(nextperiod, 0)))
253*433d6423SLionel Sambuc printf("RANDOM: sys_setalarm failed: %d\n", s);
254*433d6423SLionel Sambuc }
255*433d6423SLionel Sambuc
256*433d6423SLionel Sambuc /*===========================================================================*
257*433d6423SLionel Sambuc * r_select *
258*433d6423SLionel Sambuc *===========================================================================*/
r_select(devminor_t minor,unsigned int ops,endpoint_t ep)259*433d6423SLionel Sambuc static int r_select(devminor_t minor, unsigned int ops, endpoint_t ep)
260*433d6423SLionel Sambuc {
261*433d6423SLionel Sambuc /* random device is always writable; it's infinitely readable
262*433d6423SLionel Sambuc * once seeded, and doesn't block when it's not, so all operations
263*433d6423SLionel Sambuc * are instantly possible. we ignore CDEV_OP_ERR.
264*433d6423SLionel Sambuc */
265*433d6423SLionel Sambuc int ready_ops = 0;
266*433d6423SLionel Sambuc if (minor != RANDOM_DEV) return(EIO);
267*433d6423SLionel Sambuc return ops & (CDEV_OP_RD | CDEV_OP_WR);
268*433d6423SLionel Sambuc }
269