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