Plan 9 from Bell Labs’s /usr/web/sources/contrib/bakul/9/bcm/random.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 * See http://pastehtml.com/view/crkxyohmp.rtxt
 *
 */
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"io.h"

typedef struct RndNumGen RndNumGen;

struct RndNumGen
{
	u32int	ctl;
	u32int	stat;
	u32int	data;
	u32int	threshold;
	u32int	int_mask;
};

enum {
	RNGBASE		= VIRTIO+0x104000,
	RngCtl		= RNGBASE,
	  RngCtlG2x	= 2,		// double speed generation
	  RngCtlEna	= 1,		// enable
	RngStat		= RNGBASE + 4,
	  RngCnt	= 0xff000000,	// valid word count
	  RngCntShift	= 24,		// valid word count shift
	  RngWrmCnt	= 0x000fffff,	// warm up count
	RngData		= RNGBASE + 8,
	RngFFthresh	= RNGBASE + 12,
	  RngFFTmsk	= 0xff,		// number of words before intr
	RngIntMask	= RNGBASE + 16,
	  RngIntdis	= 1,		// write 1 to disable intr
};

struct Rb
{
	QLock;
	Rendez	producer;
	Rendez	consumer;
	ulong	randomcount;
	uchar	buf[1024];
	uchar	*ep;
	uchar	*rp;
	uchar	*wp;
	uchar	next;
	uchar	wakeme;
	ushort	bits;
	ulong	randn;
} rb;

static ulong (*rndread)(void *xp, ulong n);

static int
rbnotfull(void*)
{
	int i;

	i = rb.rp - rb.wp;
	return i != 1 && i != (1 - sizeof(rb.buf));
}

static int
rbnotempty(void*)
{
	return rb.wp != rb.rp;
}

static void
genrandom(void*)
{
	up->basepri = PriNormal;
	up->priority = up->basepri;

	for(;;){
		for(;;)
			if(++rb.randomcount > 100000)
				break;
		if(anyhigher())
			sched();
		if(!rbnotfull(0))
			sleep(&rb.producer, rbnotfull, 0);
	}
}

/*
 *  produce random bits in a circular buffer
 */
static void
randomclock(void)
{
	if(rb.randomcount == 0 || !rbnotfull(0))
		return;

	rb.bits = (rb.bits<<2) ^ rb.randomcount;
	rb.randomcount = 0;

	rb.next++;
	if(rb.next != 8/2)
		return;
	rb.next = 0;

	*rb.wp ^= rb.bits;
	if(rb.wp+1 == rb.ep)
		rb.wp = rb.buf;
	else
		rb.wp = rb.wp+1;

	if(rb.wakeme)
		wakeup(&rb.consumer);
}

static ulong
hwrandomread(void *xp, ulong n)
{
	RndNumGen* rng = (RndNumGen*)RNGBASE;
	uchar *e, *p;

	p = xp;

	if (waserror()) {
		qunlock(&rb);
		nexterror();
	}

	qlock(&rb);
	for(e = p + n; p < e; ){
		int cnt;
		u32int stat = rng->stat;
		cnt = stat >> RngCntShift;

		while (cnt > 0) {
			union { u32int i; uchar c[4];} data;
			data.i = rng->data;
			coherence();
			cnt--;
			*p++ = data.c[0]; if (p >= e) break;
			*p++ = data.c[1]; if (p >= e) break;
			*p++ = data.c[2]; if (p >= e) break;
			*p++ = data.c[3]; if (p >= e) break;
		}
	}
	qunlock(&rb);
	poperror();

	return n;
}

/*
 *  consume random bytes from a circular buffer
 */
static ulong
swrandomread(void *xp, ulong n)
{
	uchar *e, *p;
	ulong x;

	p = xp;

	if(waserror()){
		qunlock(&rb);
		nexterror();
	}

	qlock(&rb);
	for(e = p + n; p < e; ){
		if(rb.wp == rb.rp){
			rb.wakeme = 1;
			wakeup(&rb.producer);
			sleep(&rb.consumer, rbnotempty, 0);
			rb.wakeme = 0;
			continue;
		}

		/*
		 *  beating clocks will be predictable if
		 *  they are synchronized.  Use a cheap pseudo-
		 *  random number generator to obscure any cycles.
		 */
		x = rb.randn*1103515245 ^ *rb.rp;
		*p++ = rb.randn = x;

		if(rb.rp+1 == rb.ep)
			rb.rp = rb.buf;
		else
			rb.rp = rb.rp+1;
	}
	qunlock(&rb);
	poperror();

	wakeup(&rb.producer);

	return n;
}

ulong
randomread(void *xp, ulong n)
{
	return rndread(xp,n);
}

static void
hwrandominit(void)
{
	RndNumGen* rng = (RndNumGen*)RNGBASE;
	u32int ctl;

	// as per Broadcom the first 0x40000 numbers are less random. Dicard.
	rng->stat = 0x40000;
	ctl = rng->ctl;
	coherence();
	rng->ctl = ctl|RngCtlEna;
}

void
randominit(void)
{
	/* firmware support added on Wed Jan 30 13:30:14 2013 GMT */
	if (getfirmware() >= 366104) {
		rndread = hwrandomread;
		hwrandominit();
	} else {
		rndread = swrandomread;
		/* Frequency close but not equal to HZ */
		addclock0link(randomclock, 13);
		rb.ep = rb.buf + sizeof(rb.buf);
		rb.rp = rb.wp = rb.buf;
		kproc("genrandom", genrandom, 0);
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.