blob: 4e1de822c14d9153b70d06cf6271629af5a0ce7a [file] [log] [blame] [edit]
// INFERNO
#include <vfs.h>
#include <kfs.h>
#include <slab.h>
#include <kmalloc.h>
#include <kref.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <error.h>
#include <cpio.h>
#include <pmap.h>
#include <smp.h>
#include <apipe.h>
#define RAND_BUF_SZ 1024
static struct rb {
uint8_t buf[RAND_BUF_SZ];
struct atomic_pipe ap;
} rb;
/* The old style seemed to have genrandom incrementing a shared mem variable,
* randomcount, while randomclock, sort of an interrupt handler, would use this
* variable to generate random numbers. They needed to run concurrently to get
* some sort of randonmess. To do so, randomclock wouldn't run if genrandom
* wasn't in the process of incrementing the variable. So we'd need genrandom
* working (in the background, but that doesn't work so well for us), when the
* randomclock alarm fired. Then we could get 2 bits. We'd do that 4 times
* to make our random byte.
*
* In akaros, genrandom would spin to 100,000 every time, without interruption,
* since the randomcount's alarm wouldn't interrupt: they are both routine
* kernel messages. So we might as well just call kthread yield each time.
* Even then, it was still really slow. This was because we only got 2 bits of
* randomness every 13ms (randomcount would make 2 bits per run, it would run
* once every 13ms, unless I screwed up the math on that. It was supposed to
* run with a "Frequency close but not equal to HZ").
*
* We'd also use the old random values in the ring buffer to muck with the
* randomness. */
static void genrandom(void *unused)
{
uint8_t rand_two_bits, rp_byte, wp_byte;
uint8_t rand_byte = 0;
unsigned int mod_four = 0;
//setpri(PriBackground);
for (;;) {
/* this seems just as good (or bad) as the old genrandom incrementing a
* shared memory variable concurrently */
rand_two_bits = read_tsc() & 0x3;
rand_byte = (rand_byte << 2) ^ rand_two_bits;
/* put in a kthread_yield or something here, if we want to replicate the
* way randomclock would return, waiting til its next tick to get two
* more bits. */
/* every four times, we built a full random byte */
if (++mod_four % 4 == 0)
continue;
/* the old plan9 generator would xor our rand_byte with both the value
* of the read pointer and the write pointer:
* *rb.wp ^= rb.bits ^ *rb.rp;
* we'll peak into the apipe to do the same */
rp_byte = rb.buf[rb.ap.ap_rd_off & (RAND_BUF_SZ - 1)];
wp_byte = rb.buf[rb.ap.ap_wr_off & (RAND_BUF_SZ - 1)];
rand_byte ^= rp_byte ^ wp_byte;
apipe_write(&rb.ap, &rand_byte, 1);
}
}
void randominit(void)
{
apipe_init(&rb.ap, rb.buf, sizeof(rb.buf), 1);
ktask("genrandom", genrandom, 0);
}
uint32_t randomread(void *buf, uint32_t n)
{
int amt;
uint32_t ret = 0;
for (int i = 0; i < n; i++) {
/* read the random byte directly into the (user) buffer */
amt = apipe_read(&rb.ap, buf, 1);
if (amt < 0)
error("randomread apipe");
if (amt != 1)
warn("Odd amount read from random apipe");
buf++;
ret += amt;
}
return ret;
}