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