1 /* This file contains the device dependent part of the drivers for the
2 * following special files:
3 * /dev/random - random number generator
6 #include <minix/drivers.h>
7 #include <minix/chardriver.h>
8 #include <minix/type.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 static struct device m_geom
[NR_DEVS
]; /* base and size of each device */
19 static dev_t m_device
; /* current device */
21 extern int errno
; /* error number for PM calls */
23 static struct device
*r_prepare(dev_t device
);
24 static int r_transfer(endpoint_t endpt
, int opcode
, u64_t position
,
25 iovec_t
*iov
, unsigned int nr_req
, endpoint_t user_endpt
, unsigned int
27 static int r_do_open(message
*m_ptr
);
28 static void r_random(message
*m_ptr
);
29 static void r_updatebin(int source
, struct k_randomness_bin
*rb
);
31 /* Entry points to this driver. */
32 static struct chardriver r_dtab
= {
33 r_do_open
, /* open or mount */
34 do_nop
, /* nothing on a close */
35 nop_ioctl
, /* no I/O controls supported */
36 r_prepare
, /* prepare for I/O on a given minor device */
37 r_transfer
, /* do the I/O */
38 nop_cleanup
, /* no need to clean up */
39 r_random
, /* get randomness from kernel (alarm) */
40 nop_cancel
, /* cancel not supported */
41 nop_select
, /* select not supported */
42 NULL
, /* other messages not supported */
45 /* Buffer for the /dev/random number generator. */
46 #define RANDOM_BUF_SIZE 1024
47 static char random_buf
[RANDOM_BUF_SIZE
];
49 /* SEF functions and variables. */
50 static void sef_local_startup(void);
51 static int sef_cb_init_fresh(int type
, sef_init_info_t
*info
);
53 /*===========================================================================*
55 *===========================================================================*/
58 /* SEF local startup. */
61 /* Call the generic receive loop. */
62 chardriver_task(&r_dtab
, CHARDRIVER_ASYNC
);
67 /*===========================================================================*
69 *===========================================================================*/
70 static void sef_local_startup()
72 /* Register init callbacks. */
73 sef_setcb_init_fresh(sef_cb_init_fresh
);
74 sef_setcb_init_lu(sef_cb_init_fresh
);
75 sef_setcb_init_restart(sef_cb_init_fresh
);
77 /* Register live update callbacks. */
78 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready
);
79 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard
);
81 /* Let SEF perform startup. */
85 /*===========================================================================*
87 *===========================================================================*/
88 static int sef_cb_init_fresh(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
90 /* Initialize the random driver. */
91 static struct k_randomness krandom
;
95 r_random(NULL
); /* also set periodic timer */
97 /* Retrieve first randomness buffer with parameters. */
98 if (OK
!= (s
=sys_getrandomness(&krandom
))) {
99 printf("RANDOM: sys_getrandomness failed: %d\n", s
);
103 /* Do sanity check on parameters. */
104 if(krandom
.random_sources
!= RANDOM_SOURCES
||
105 krandom
.random_elements
!= RANDOM_ELEMENTS
) {
106 printf("random: parameters (%d, %d) don't match kernel's (%d, %d)\n",
107 RANDOM_SOURCES
, RANDOM_ELEMENTS
,
108 krandom
.random_sources
, krandom
.random_elements
);
112 /* Feed initial batch. */
113 for(i
= 0; i
< RANDOM_SOURCES
; i
++)
114 r_updatebin(i
, &krandom
.bin
[i
]);
116 /* Announce we are up! */
117 chardriver_announce();
122 /*===========================================================================*
124 *===========================================================================*/
125 static struct device
*r_prepare(dev_t device
)
127 /* Prepare for I/O on a device: check if the minor device number is ok. */
129 if (device
>= NR_DEVS
) return(NULL
);
132 return(&m_geom
[device
]);
135 /*===========================================================================*
137 *===========================================================================*/
138 static int r_transfer(
139 endpoint_t endpt
, /* endpoint of grant owner */
140 int opcode
, /* DEV_GATHER or DEV_SCATTER */
141 u64_t position
, /* offset on device to read or write */
142 iovec_t
*iov
, /* pointer to read or write request vector */
143 unsigned int nr_req
, /* length of request vector */
144 endpoint_t
UNUSED(user_endpt
),/* endpoint of user process */
145 unsigned int UNUSED(flags
)
148 /* Read or write one the driver's minor devices. */
149 unsigned count
, left
, chunk
;
153 size_t vir_offset
= 0;
155 /* Get minor device number and check for /dev/null. */
156 dv
= &m_geom
[m_device
];
160 /* How much to transfer and where to / from. */
161 count
= iov
->iov_size
;
162 grant
= (cp_grant_id_t
) iov
->iov_addr
;
166 /* Random number generator. Character instead of block device. */
168 if (opcode
== DEV_GATHER_S
&& !random_isseeded())
172 chunk
= (left
> RANDOM_BUF_SIZE
) ? RANDOM_BUF_SIZE
: left
;
173 if (opcode
== DEV_GATHER_S
) {
174 random_getbytes(random_buf
, chunk
);
175 r
= sys_safecopyto(endpt
, grant
, vir_offset
,
176 (vir_bytes
) random_buf
, chunk
);
179 printf("random: sys_safecopyto failed for proc %d, "
180 "grant %d\n", endpt
, grant
);
183 } else if (opcode
== DEV_SCATTER_S
) {
184 r
= sys_safecopyfrom(endpt
, grant
, vir_offset
,
185 (vir_bytes
) random_buf
, chunk
);
188 printf("random: sys_safecopyfrom failed for proc %d, "
189 "grant %d\n", endpt
, grant
);
192 random_putbytes(random_buf
, chunk
);
199 /* Unknown (illegal) minor device. */
204 /* Book the number of bytes transferred. */
205 position
= add64u(position
, count
);
206 if ((iov
->iov_size
-= count
) == 0) { iov
++; nr_req
--; vir_offset
= 0; }
212 /*===========================================================================*
214 *===========================================================================*/
215 static int r_do_open(message
*m_ptr
)
217 /* Check device number on open.
219 if (r_prepare(m_ptr
->DEVICE
) == NULL
) return(ENXIO
);
224 #define UPDATE(binnumber, bp, startitem, elems) { \
226 int n = elems, item = startitem;\
228 assert(binnumber >= 0 && binnumber < RANDOM_SOURCES); \
229 assert(item >= 0 && item < RANDOM_ELEMENTS); \
232 assert(high >= item); \
233 assert(high >= 0 && high < RANDOM_ELEMENTS); \
234 r = &bp->r_buf[item]; \
235 random_update(binnumber, r, n); \
239 /*===========================================================================*
241 *===========================================================================*/
242 static void r_updatebin(int source
, struct k_randomness_bin
*rb
)
244 int r_next
, r_size
, r_high
;
249 assert(r_next
>= 0 && r_next
< RANDOM_ELEMENTS
);
250 assert(r_size
>= 0 && r_size
<= RANDOM_ELEMENTS
);
252 r_high
= r_next
+r_size
;
254 if (r_high
<= RANDOM_ELEMENTS
) {
255 UPDATE(source
, rb
, r_next
, r_size
);
257 assert(r_next
< RANDOM_ELEMENTS
);
258 UPDATE(source
, rb
, r_next
, RANDOM_ELEMENTS
-r_next
);
259 UPDATE(source
, rb
, 0, r_high
-RANDOM_ELEMENTS
);
265 /*===========================================================================*
267 *===========================================================================*/
268 static void r_random(message
*UNUSED(m_ptr
))
270 /* Fetch random information from the kernel to update /dev/random. */
273 static struct k_randomness_bin krandom_bin
;
276 int nextperiod
= random_isseeded() ? KRANDOM_PERIOD
*500 : KRANDOM_PERIOD
;
278 bin
= (bin
+1) % RANDOM_SOURCES
;
280 if(sys_getrandom_bin(&krandom_bin
, bin
) == OK
)
281 r_updatebin(bin
, &krandom_bin
);
283 /* Add our own timing source. */
286 random_update(RND_TIMING
, &r
, 1);
288 /* Schedule new alarm for next m_random call. */
289 if (OK
!= (s
=sys_setalarm(nextperiod
, 0)))
290 printf("RANDOM: sys_setalarm failed: %d\n", s
);