#include "../drivers.h"
#include "../libdriver/driver.h"
#include <sys/ioc_memory.h>
-#include "../../kernel/const.h"
-#include "../../kernel/config.h"
-#include "../../kernel/type.h"
+#include <minix/type.h>
#include "assert.h"
#include "random.h"
FORWARD _PROTOTYPE( int r_ioctl, (struct driver *dp, message *m_ptr, int safe) );
FORWARD _PROTOTYPE( void r_geometry, (struct partition *entry) );
FORWARD _PROTOTYPE( void r_random, (struct driver *dp, message *m_ptr) );
+FORWARD _PROTOTYPE( void r_updatebin, (int source, struct k_randomness_bin *rb));
/* Entry points to this driver. */
PRIVATE struct driver r_dtab = {
*===========================================================================*/
PRIVATE void r_init()
{
- /* Initialize this task. All minor devices are initialized one by one. */
+ static struct k_randomness krandom;
+ int i, s;
+
random_init();
r_random(NULL, NULL); /* also set periodic timer */
+
+ /* Retrieve first randomness buffer with parameters. */
+ if (OK != (s=sys_getrandomness(&krandom))) {
+ report("RANDOM", "sys_getrandomness failed", s);
+ exit(1);
+ }
+
+ /* Do sanity check on parameters. */
+ if(krandom.random_sources != RANDOM_SOURCES ||
+ krandom.random_elements != RANDOM_ELEMENTS) {
+ printf("random: parameters (%d, %d) don't match kernel's (%d, %d)\n",
+ RANDOM_SOURCES, RANDOM_ELEMENTS,
+ krandom.random_sources, krandom.random_elements);
+ exit(1);
+ }
+
+ /* Feed initial batch. */
+ for(i = 0; i < RANDOM_SOURCES; i++)
+ r_updatebin(i, &krandom.bin[i]);
}
/*===========================================================================*
return(OK);
}
+#define UPDATE(binnumber, bp, startitem, elems) { \
+ rand_t *r, *r2; \
+ int n = elems, item = startitem;\
+ int high; \
+ assert(binnumber >= 0 && binnumber < RANDOM_SOURCES); \
+ assert(item >= 0 && item < RANDOM_ELEMENTS); \
+ if(n > 0) { \
+ high = item+n-1; \
+ assert(high >= item); \
+ assert(high >= 0 && high < RANDOM_ELEMENTS); \
+ r = &bp->r_buf[item]; \
+ r2 = &bp->r_buf[high]; \
+ random_update(binnumber, r, n); \
+ } \
+}
+
+PRIVATE void r_updatebin(int source, struct k_randomness_bin *rb)
+{
+ int r_next, r_size, r_high;
+
+ r_next= rb->r_next;
+ r_size= rb->r_size;
+
+ assert(r_next >= 0 && r_next < RANDOM_ELEMENTS);
+ assert(r_size >= 0 && r_size <= RANDOM_ELEMENTS);
+
+ r_high= r_next+r_size;
+
+ if (r_high <= RANDOM_ELEMENTS) {
+ UPDATE(source, rb, r_next, r_size);
+ } else {
+ assert(r_next < RANDOM_ELEMENTS);
+ UPDATE(source, rb, r_next, RANDOM_ELEMENTS-r_next);
+ UPDATE(source, rb, 0, r_high-RANDOM_ELEMENTS);
+ }
+
+ return;
+}
+
/*============================================================================*
* r_random *
*============================================================================*/
message *m_ptr; /* pointer to alarm message */
{
/* Fetch random information from the kernel to update /dev/random. */
- int i, s, r_next, r_size, r_high;
- struct randomness krandom;
+ int s;
+ static int bin = 0;
+ static struct k_randomness_bin krandom_bin;
+ u32_t hi, lo;
+ rand_t r;
- if (OK != (s=sys_getrandomness(&krandom)))
- report("RANDOM", "sys_getrandomness failed", s);
+ bin = (bin+1) % RANDOM_SOURCES;
- for (i= 0; i<RANDOM_SOURCES; i++)
- {
- r_next= krandom.bin[i].r_next;
- r_size= krandom.bin[i].r_size;
- r_high= r_next+r_size;
- if (r_high <= RANDOM_ELEMENTS)
- {
- random_update(i, &krandom.bin[i].r_buf[r_next], r_size);
- }
- else
- {
- assert(r_next < RANDOM_ELEMENTS);
- random_update(i, &krandom.bin[i].r_buf[r_next],
- RANDOM_ELEMENTS-r_next);
- random_update(i, &krandom.bin[i].r_buf[0],
- r_high-RANDOM_ELEMENTS);
- }
- }
+ if(sys_getrandom_bin(&krandom_bin, bin) == OK)
+ r_updatebin(bin, &krandom_bin);
+
+ /* Add our own timing source. */
+ read_tsc(&hi, &lo);
+ r = lo;
+ random_update(RND_TIMING, &r, 1);
/* Schedule new alarm for next m_random call. */
if (OK != (s=sys_setalarm(KRANDOM_PERIOD, 0)))
* re-seed.
*/
-PRIVATE unsigned long deriv[RANDOM_SOURCES][N_DERIV];
-PRIVATE int pool_ind[RANDOM_SOURCES];
+PRIVATE unsigned long deriv[TOTAL_SOURCES][N_DERIV];
+PRIVATE int pool_ind[TOTAL_SOURCES];
PRIVATE SHA256_CTX pool_ctx[NR_POOLS];
PRIVATE unsigned samples= 0;
PRIVATE int got_seeded= 0;
{
int i, j;
- assert(&deriv[RANDOM_SOURCES-1][N_DERIV-1] ==
- &deriv[0][0] + RANDOM_SOURCES*N_DERIV -1);
+ assert(&deriv[TOTAL_SOURCES-1][N_DERIV-1] ==
+ &deriv[0][0] + TOTAL_SOURCES*N_DERIV -1);
- for (i= 0; i<RANDOM_SOURCES; i++)
+ for (i= 0; i<TOTAL_SOURCES; i++)
{
for (j= 0; j<N_DERIV; j++)
deriv[i][j]= 0;
PUBLIC void random_update(source, buf, count)
int source;
-unsigned short *buf;
+rand_t *buf;
int count;
{
int i;
#if 0
printf("random_update: got %d samples for source %d\n", count, source);
#endif
- if (source < 0 || source >= RANDOM_SOURCES)
+ if (source < 0 || source >= TOTAL_SOURCES)
panic("memory", "random_update: bad source", source);
for (i= 0; i<count; i++)
add_sample(source, buf[i]);
Public interface to the random number generator
*/
+/* Internal random sources */
+#define RND_TIMING 0
+#define RANDOM_SOURCES_INTERNAL 1
+#define TOTAL_SOURCES (RANDOM_SOURCES+RANDOM_SOURCES_INTERNAL)
+
_PROTOTYPE( void random_init, (void) );
_PROTOTYPE( int random_isseeded, (void) );
-_PROTOTYPE( void random_update, (int source, unsigned short *buf,
- int count) );
+_PROTOTYPE( void random_update, (int source, rand_t *buf, int count) );
_PROTOTYPE( void random_getbytes, (void *buf, size_t size) );
_PROTOTYPE( void random_putbytes, (void *buf, size_t size) );
# define GET_PRIVID 17 /* get ID of privilege structure */
# define GET_HZ 18 /* get HZ value */
# define GET_WHOAMI 19 /* get own name and endpoint */
+# define GET_RANDOMNESS_BIN 20 /* get one randomness bin */
#define I_ENDPT m7_i4 /* calling process */
#define I_VAL_PTR m7_p1 /* virtual address at caller */
#define I_VAL_LEN m7_i1 /* max length of value */
#define sys_getprivtab(dst) sys_getinfo(GET_PRIVTAB, dst, 0,0,0)
#define sys_getproc(dst,nr) sys_getinfo(GET_PROC, dst, 0,0, nr)
#define sys_getrandomness(dst) sys_getinfo(GET_RANDOMNESS, dst, 0,0,0)
+#define sys_getrandom_bin(d,b) sys_getinfo(GET_RANDOMNESS_BIN, d, 0,0,b)
#define sys_getimage(dst) sys_getinfo(GET_IMAGE, dst, 0,0,0)
#define sys_getirqhooks(dst) sys_getinfo(GET_IRQHOOKS, dst, 0,0,0)
#define sys_getirqactids(dst) sys_getinfo(GET_IRQACTIDS, dst, 0,0,0)
_PROTOTYPE( u32_t micros_to_ticks, (u32_t micros));
_PROTOTYPE( int asynsend, (endpoint_t ep, message *msg));
_PROTOTYPE( void ser_putc, (char c));
+_PROTOTYPE( void get_randomness, (struct k_randomness *, int));
+
#define ASSERT(c) if(!(c)) { panic(__FILE__, "assert " #c " failed at line", __LINE__); }
char km_buf[_KMESS_BUF_SIZE]; /* buffer for messages */
};
+#include <ibm/interrupt.h>
+
+/* randomness struct: random sources after interrupts: */
+#define RANDOM_SOURCES NR_IRQ_VECTORS
+#define RANDOM_ELEMENTS 64
+
+typedef unsigned short rand_t;
+
+struct k_randomness {
+ int random_elements, random_sources;
+ struct k_randomness_bin {
+ int r_next; /* next index to write */
+ int r_size; /* number of random elements */
+ rand_t r_buf[RANDOM_ELEMENTS]; /* buffer for random info */
+ } bin[RANDOM_SOURCES];
+};
#endif /* _TYPE_H */
* not very random.
*/
lock;
- get_randomness(CLOCK_IRQ);
+ get_randomness(&krandom, CLOCK_IRQ);
unlock;
return(OK);
*/
#define P_NAME_LEN 8
-/* Buffer to gather randomness. This is used to generate a random stream by
- * the MEMORY driver when reading from /dev/random.
- */
-#define RANDOM_ELEMENTS 32
-
/* This section contains defines for valuable system resources that are used
* by device drivers. The number of elements of the vectors is determined by
* the maximum needed by any given driver. The number of interrupt hooks may
#define _SRC_ 0
#define _DST_ 1
-/* Number of random sources */
-#define RANDOM_SOURCES 16
-
#define get_sys_bit(map,bit) \
( MAP_CHUNK(map.chunk,bit) & (1 << CHUNK_OFFSET(bit) )
#define get_sys_bits(map,bit) \
EXTERN struct kinfo kinfo; /* kernel information for users */
EXTERN struct machine machine; /* machine information for users */
EXTERN struct kmessages kmess; /* diagnostic messages in kernel */
-EXTERN struct randomness krandom; /* gather kernel random information */
+EXTERN struct k_randomness krandom; /* gather kernel random information */
EXTERN struct loadinfo kloadinfo; /* status of load average */
/* Process scheduling information and the kernel reentry count. */
cprof_procs_no = 0; /* init nr of hash table slots used */
vm_running = 0;
+ krandom.random_sources = RANDOM_SOURCES;
+ krandom.random_elements = RANDOM_ELEMENTS;
/* MINIX is now ready. All boot image processes are on the ready queue.
* Return to the assembly code to start running the current process.
_PROTOTYPE( void send_sig, (int proc_nr, int sig_nr) );
_PROTOTYPE( void cause_sig, (int proc_nr, int sig_nr) );
_PROTOTYPE( void sys_task, (void) );
-_PROTOTYPE( void get_randomness, (int source) );
#define numap_local(proc_nr, vir_addr, bytes) \
umap_local(proc_addr(proc_nr), D, (vir_addr), (bytes))
_PROTOTYPE( phys_bytes umap_grant, (struct proc *, cp_grant_id_t,
return(OK);
}
-/*===========================================================================*
- * get_randomness *
- *===========================================================================*/
-PUBLIC void get_randomness(source)
-int source;
-{
-/* Use architecture-dependent high-resolution clock for
- * raw entropy gathering.
- */
- int r_next;
- unsigned long tsc_high, tsc_low;
-
- source %= RANDOM_SOURCES;
- r_next= krandom.bin[source].r_next;
- read_tsc(&tsc_high, &tsc_low);
- krandom.bin[source].r_buf[r_next] = tsc_low;
- if (krandom.bin[source].r_size < RANDOM_ELEMENTS) {
- krandom.bin[source].r_size ++;
- }
- krandom.bin[source].r_next = (r_next + 1 ) % RANDOM_ELEMENTS;
-}
-
/*===========================================================================*
* send_sig *
*===========================================================================*/
int proc_nr, nr_e, nr;
struct proc *caller;
phys_bytes ph;
+ int wipe_rnd_bin = -1;
caller = proc_addr(who_p);
break;
}
case GET_RANDOMNESS: {
- static struct randomness copy; /* copy to keep counters */
+ static struct k_randomness copy; /* copy to keep counters */
int i;
copy = krandom;
krandom.bin[i].r_size = 0; /* invalidate random data */
krandom.bin[i].r_next = 0;
}
- length = sizeof(struct randomness);
+ length = sizeof(copy);
src_vir = (vir_bytes) ©
break;
}
+ case GET_RANDOMNESS_BIN: {
+ int i, bin = m_ptr->I_VAL_LEN2_E;
+
+ if(bin < 0 || bin >= RANDOM_SOURCES) {
+ kprintf("SYSTEM: GET_RANDOMNESS_BIN: %d out of range\n", bin);
+ return EINVAL;
+ }
+
+ if(krandom.bin[bin].r_size < RANDOM_ELEMENTS)
+ return ENOENT;
+
+ length = sizeof(krandom.bin[bin]);
+ src_vir = (vir_bytes) &krandom.bin[bin];
+
+ wipe_rnd_bin = bin;
+
+ break;
+ }
case GET_KMESSAGES: {
length = sizeof(struct kmessages);
src_vir = (vir_bytes) &kmess;
if((ph=umap_local(caller, D, (vir_bytes) m_ptr->I_VAL_PTR,length)) == 0)
return EFAULT;
CHECKRANGE_OR_SUSPEND(caller, ph, length, 1);
- data_copy(SYSTEM, src_vir, who_e, (vir_bytes) m_ptr->I_VAL_PTR, length);
+ if(data_copy(SYSTEM, src_vir, who_e, (vir_bytes) m_ptr->I_VAL_PTR, length) == OK) {
+ if(wipe_rnd_bin >= 0 && wipe_rnd_bin < RANDOM_SOURCES) {
+ krandom.bin[wipe_rnd_bin].r_size = 0;
+ krandom.bin[wipe_rnd_bin].r_next = 0;
+ }
+ }
return(OK);
}
/* As a side-effect, the interrupt handler gathers random information by
* timestamping the interrupt events. This is used for /dev/random.
*/
- get_randomness(hook->irq);
+ get_randomness(&krandom, hook->irq);
/* Check if the handler is still alive.
* If it's dead, this should never happen, as processes that die
#define TYPE_H
#include <minix/com.h>
+#include <ibm/interrupt.h>
typedef _PROTOTYPE( void task_t, (void) );
endpoint_t endpoint; /* endpoint number when started */
};
-struct randomness {
- struct {
- int r_next; /* next index to write */
- int r_size; /* number of random elements */
- unsigned short r_buf[RANDOM_ELEMENTS]; /* buffer for random info */
- } bin[RANDOM_SOURCES];
-};
-
typedef unsigned long irq_policy_t;
typedef unsigned long irq_id_t;
kprintf.c \
kputc.c \
tickdelay.c \
+ get_randomness.c \
getuptime.c \
getuptime2.c \
env_get_prm.c \
--- /dev/null
+#include <lib.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <minix/profile.h>
+#include <minix/syslib.h>
+#include <minix/type.h>
+#include <minix/sysutil.h>
+
+/*===========================================================================*
+ * get_randomness *
+ *===========================================================================*/
+PUBLIC void get_randomness(rand, source)
+struct k_randomness *rand;
+int source;
+{
+/* Use architecture-dependent high-resolution clock for
+ * raw entropy gathering.
+ */
+ int r_next;
+ unsigned long tsc_high, tsc_low;
+
+ source %= RANDOM_SOURCES;
+ r_next= rand->bin[source].r_next;
+ read_tsc(&tsc_high, &tsc_low);
+ rand->bin[source].r_buf[r_next] = tsc_low;
+ if (rand->bin[source].r_size < RANDOM_ELEMENTS) {
+ rand->bin[source].r_size ++;
+ }
+ rand->bin[source].r_next = (r_next + 1 ) % RANDOM_ELEMENTS;
+}
+
+