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 "../drivers.h"
7 #include "../libdriver/driver.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 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) */
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 /*===========================================================================*
61 *===========================================================================*/
64 /* SEF local startup. */
67 /* Call the generic receive loop. */
68 driver_task(&r_dtab
, DRIVER_ASYN
);
73 /*===========================================================================*
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. */
91 /*===========================================================================*
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
;
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
);
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
);
118 /* Feed initial batch. */
119 for(i
= 0; i
< RANDOM_SOURCES
; i
++)
120 r_updatebin(i
, &krandom
.bin
[i
]);
125 /*===========================================================================*
127 *===========================================================================*/
128 PRIVATE
char *r_name()
130 /* Return a name for the current device. */
131 static char name
[] = "random";
135 /*===========================================================================*
137 *===========================================================================*/
138 PRIVATE
struct device
*r_prepare(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
);
146 return(&m_geom
[device
]);
149 /*===========================================================================*
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
;
164 size_t vir_offset
= 0;
166 /* Get minor device number and check for /dev/null. */
167 dv
= &m_geom
[m_device
];
171 /* How much to transfer and where to / from. */
172 count
= iov
->iov_size
;
173 user_vir
= iov
->iov_addr
;
177 /* Random number generator. Character instead of block device. */
179 if (opcode
== DEV_GATHER_S
&& !random_isseeded())
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
);
191 "random: sys_safecopyto failed for proc %d, grant %d\n",
195 } else if (opcode
== DEV_SCATTER_S
) {
196 r
= sys_safecopyfrom(proc_nr
, user_vir
, vir_offset
,
197 (vir_bytes
) random_buf
, chunk
, D
);
201 "random: sys_safecopyfrom failed for proc %d, grant %d\n",
205 random_putbytes(random_buf
, chunk
);
212 /* Unknown (illegal) minor device. */
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; }
225 /*============================================================================*
227 *============================================================================*/
228 PRIVATE
int r_do_open(dp
, m_ptr
)
232 /* Check device number on open.
234 if (r_prepare(m_ptr
->DEVICE
) == NIL_DEV
) return(ENXIO
);
239 /*===========================================================================*
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
) {
251 return(do_diocntl(&r_dtab
, m_ptr
));
256 #define UPDATE(binnumber, bp, startitem, elems) { \
258 int n = elems, item = startitem;\
260 assert(binnumber >= 0 && binnumber < RANDOM_SOURCES); \
261 assert(item >= 0 && item < RANDOM_ELEMENTS); \
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
;
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
);
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
);
294 /*============================================================================*
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. */
304 static struct k_randomness_bin krandom_bin
;
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. */
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 /*============================================================================*
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);