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_lu(sef_cb_init_fresh); 75 sef_setcb_init_restart(sef_cb_init_fresh); 76 77 /* Let SEF perform startup. */ 78 sef_startup(); 79 } 80 81 /*===========================================================================* 82 * sef_cb_init_fresh * 83 *===========================================================================*/ 84 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) 85 { 86 /* Initialize the random driver. */ 87 static struct k_randomness krandom; 88 int i, s; 89 90 random_init(); 91 r_random(0); /* also set periodic timer */ 92 93 /* Retrieve first randomness buffer with parameters. */ 94 if (OK != (s=sys_getrandomness(&krandom))) { 95 printf("RANDOM: sys_getrandomness failed: %d\n", s); 96 exit(1); 97 } 98 99 /* Do sanity check on parameters. */ 100 if(krandom.random_sources != RANDOM_SOURCES || 101 krandom.random_elements != RANDOM_ELEMENTS) { 102 printf("random: parameters (%d, %d) don't match kernel's (%d, %d)\n", 103 RANDOM_SOURCES, RANDOM_ELEMENTS, 104 krandom.random_sources, krandom.random_elements); 105 exit(1); 106 } 107 108 /* Feed initial batch. */ 109 for(i = 0; i < RANDOM_SOURCES; i++) 110 r_updatebin(i, &krandom.bin[i]); 111 112 /* Announce we are up! */ 113 chardriver_announce(); 114 115 return(OK); 116 } 117 118 /*===========================================================================* 119 * r_read * 120 *===========================================================================*/ 121 static ssize_t r_read(devminor_t minor, u64_t UNUSED(position), 122 endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), 123 cdev_id_t UNUSED(id)) 124 { 125 /* Read from one of the driver's minor devices. */ 126 size_t offset, chunk; 127 int r; 128 129 if (minor != RANDOM_DEV) return(EIO); 130 131 if (!random_isseeded()) return(EAGAIN); 132 133 for (offset = 0; offset < size; offset += chunk) { 134 chunk = MIN(size - offset, RANDOM_BUF_SIZE); 135 random_getbytes(random_buf, chunk); 136 r = sys_safecopyto(endpt, grant, offset, (vir_bytes)random_buf, chunk); 137 if (r != OK) { 138 printf("random: sys_safecopyto failed for proc %d, grant %d\n", 139 endpt, grant); 140 return r; 141 } 142 } 143 144 return size; 145 } 146 147 /*===========================================================================* 148 * r_write * 149 *===========================================================================*/ 150 static ssize_t r_write(devminor_t minor, u64_t UNUSED(position), 151 endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), 152 cdev_id_t UNUSED(id)) 153 { 154 /* Write to one of the driver's minor devices. */ 155 size_t offset, chunk; 156 int r; 157 158 if (minor != RANDOM_DEV) return(EIO); 159 160 for (offset = 0; offset < size; offset += chunk) { 161 chunk = MIN(size - offset, RANDOM_BUF_SIZE); 162 r = sys_safecopyfrom(endpt, grant, offset, (vir_bytes)random_buf, 163 chunk); 164 if (r != OK) { 165 printf("random: sys_safecopyfrom failed for proc %d," 166 " grant %d\n", endpt, grant); 167 return r; 168 } 169 random_putbytes(random_buf, chunk); 170 } 171 172 return size; 173 } 174 175 /*===========================================================================* 176 * r_open * 177 *===========================================================================*/ 178 static int r_open(devminor_t minor, int access, endpoint_t UNUSED(user_endpt)) 179 { 180 /* Check device number on open. 181 */ 182 183 if (minor < 0 || minor >= NR_DEVS) return(ENXIO); 184 185 return(OK); 186 } 187 188 #define UPDATE(binnumber, bp, startitem, elems) { \ 189 rand_t *r; \ 190 int n = elems, item = startitem;\ 191 int high; \ 192 assert(binnumber >= 0 && binnumber < RANDOM_SOURCES); \ 193 assert(item >= 0 && item < RANDOM_ELEMENTS); \ 194 if(n > 0) { \ 195 high = item+n-1; \ 196 assert(high >= item); \ 197 assert(high >= 0 && high < RANDOM_ELEMENTS); \ 198 r = &bp->r_buf[item]; \ 199 random_update(binnumber, r, n); \ 200 } \ 201 } 202 203 /*===========================================================================* 204 * r_updatebin * 205 *===========================================================================*/ 206 static void r_updatebin(int source, struct k_randomness_bin *rb) 207 { 208 int r_next, r_size, r_high; 209 210 r_next= rb->r_next; 211 r_size= rb->r_size; 212 213 assert(r_next >= 0 && r_next < RANDOM_ELEMENTS); 214 assert(r_size >= 0 && r_size <= RANDOM_ELEMENTS); 215 216 r_high= r_next+r_size; 217 218 if (r_high <= RANDOM_ELEMENTS) { 219 UPDATE(source, rb, r_next, r_size); 220 } else { 221 assert(r_next < RANDOM_ELEMENTS); 222 UPDATE(source, rb, r_next, RANDOM_ELEMENTS-r_next); 223 UPDATE(source, rb, 0, r_high-RANDOM_ELEMENTS); 224 } 225 226 return; 227 } 228 229 /*===========================================================================* 230 * r_random * 231 *===========================================================================*/ 232 static void r_random(clock_t UNUSED(stamp)) 233 { 234 /* Fetch random information from the kernel to update /dev/random. */ 235 int s; 236 static int bin = 0; 237 static struct k_randomness_bin krandom_bin; 238 u32_t hi, lo; 239 rand_t r; 240 int nextperiod = random_isseeded() ? KRANDOM_PERIOD*500 : KRANDOM_PERIOD; 241 242 bin = (bin+1) % RANDOM_SOURCES; 243 244 if(sys_getrandom_bin(&krandom_bin, bin) == OK) 245 r_updatebin(bin, &krandom_bin); 246 247 /* Add our own timing source. */ 248 read_tsc(&hi, &lo); 249 r = lo; 250 random_update(RND_TIMING, &r, 1); 251 252 /* Schedule new alarm for next m_random call. */ 253 if (OK != (s=sys_setalarm(nextperiod, 0))) 254 printf("RANDOM: sys_setalarm failed: %d\n", s); 255 } 256 257 /*===========================================================================* 258 * r_select * 259 *===========================================================================*/ 260 static int r_select(devminor_t minor, unsigned int ops, endpoint_t ep) 261 { 262 /* random device is always writable; it's infinitely readable 263 * once seeded, and doesn't block when it's not, so all operations 264 * are instantly possible. we ignore CDEV_OP_ERR. 265 */ 266 int ready_ops = 0; 267 if (minor != RANDOM_DEV) return(EIO); 268 return ops & (CDEV_OP_RD | CDEV_OP_WR); 269 } 270