xref: /minix3/minix/drivers/system/random/main.c (revision 1aad172900a22f403baf366fb7db7ee4560c7544)
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