shithub: riscv

Download patch

ref: 0a5f81a44230cbd562b6d71a0a5be018e24a5ba6
parent: 71ac88392f2033256b29f22bd8afdd7374100e5a
author: cinap_lenrek <[email protected]>
date: Sat Aug 27 16:42:31 EDT 2016

kernel: switch to fast portable chacha based seed-once random number generator

--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -872,6 +872,11 @@
 		fprestore = fpx87restore;
 	}
 
+	if(strcmp(m->cpuidid, "GenuineIntel") == 0 && (m->cpuidcx & Rdrnd) != 0)
+		hwrandbuf = rdrandbuf;
+	else
+		hwrandbuf = nil;
+
 	cputype = t;
 	return t->family;
 }
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -32,6 +32,7 @@
 	proc.$O\
 	qio.$O\
 	qlock.$O\
+	random.$O\
 	rdb.$O\
 	rebootcmd.$O\
 	segment.$O\
@@ -52,7 +53,6 @@
 	memory.$O\
 	mmu.$O\
 	trap.$O\
-	pcrandom.$O\
 	$CONF.root.$O\
 	$CONF.rootc.$O\
 	$DEVS\
--- a/sys/src/9/pc/pcrandom.c
+++ /dev/null
@@ -1,152 +1,0 @@
-#include	"u.h"
-#include	"../port/lib.h"
-#include	"mem.h"
-#include	"dat.h"
-#include	"fns.h"
-#include	"../port/error.h"
-
-static int haverdrand;
-
-struct Rb
-{
-	QLock;
-	Rendez	producer;
-	Rendez	consumer;
-	ulong	randomcount;
-	uchar	buf[128];
-	uchar	*ep;
-	uchar	*rp;
-	uchar	*wp;
-	uchar	next;
-	uchar	wakeme;
-	ushort	bits;
-	ulong	randn;
-} rb;
-
-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;
-
-	while(waserror())
-		;
-	for(;;){
-		if(++rb.randomcount <= 100000)
-			continue;
-		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);
-}
-
-void
-randominit(void)
-{
-	if(!strcmp(m->cpuidid, "GenuineIntel")
-		 && (m->cpuidcx & Rdrnd)){
-		haverdrand = 1;
-	}
-	else{
-		/* Frequency close but not equal to HZ */
-		addclock0link(randomclock, MS2HZ+3);
-		rb.ep = rb.buf + sizeof(rb.buf);
-		rb.rp = rb.wp = rb.buf;
-		kproc("genrandom", genrandom, 0);
-	}
-}
-
-/*
- *  consume random bytes from a circular buffer
- */
-ulong
-randomread(void *xp, ulong n)
-{
-	uchar *e, *p;
-	ulong x;
-
-	p = xp;
-
-	if(haverdrand){
-		rdrandbuf(p, n);
-		return n;
-	}
-
-	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;
-}
--- a/sys/src/9/pc64/mkfile
+++ b/sys/src/9/pc64/mkfile
@@ -29,6 +29,7 @@
 	proc.$O\
 	qio.$O\
 	qlock.$O\
+	random.$O\
 	rdb.$O\
 	rebootcmd.$O\
 	segment.$O\
@@ -49,7 +50,6 @@
 	memory.$O\
 	mmu.$O\
 	trap.$O\
-	pcrandom.$O\
 	$CONF.root.$O\
 	$CONF.rootc.$O\
 	$DEVS\
--- a/sys/src/9/port/devcons.c
+++ b/sys/src/9/port/devcons.c
@@ -4,8 +4,8 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"../port/error.h"
-#include	"pool.h"
 
+#include	<pool.h>
 #include	<authsrv.h>
 
 void	(*consdebug)(void) = nil;
@@ -21,7 +21,6 @@
 char	*sysname;
 vlong	fasthz;
 
-static void	seedrand(void);
 static int	readtime(ulong, char*, int);
 static int	readbintime(char*, int);
 static int	writetime(char*, int);
@@ -616,7 +615,8 @@
 			"%lud/%lud user\n"
 			"%lud/%lud swap\n"
 			"%llud/%llud/%llud kernel malloc\n"
-			"%llud/%llud/%llud kernel draw\n",
+			"%llud/%llud/%llud kernel draw\n"
+			"%llud/%llud/%llud kernel secret\n",
 			(uvlong)conf.npage*BY2PG,
 			(uvlong)BY2PG,
 			conf.npage-conf.upages,
@@ -627,7 +627,10 @@
 			(uvlong)mainmem->maxsize,
 			(uvlong)imagmem->curalloc,
 			(uvlong)imagmem->cursize,
-			(uvlong)imagmem->maxsize);
+			(uvlong)imagmem->maxsize,
+			(uvlong)secrmem->curalloc,
+			(uvlong)secrmem->cursize,
+			(uvlong)secrmem->maxsize);
 
 		return readstr((ulong)offset, buf, n, tmp);
 
@@ -845,29 +848,20 @@
 
 static	ulong	randn;
 
-static void
-seedrand(void)
-{
-	if(!waserror()){
-		randomread((void*)&randn, sizeof(randn));
-		poperror();
-	}
-}
-
 int
-nrand(int n)
+rand(void)
 {
 	if(randn == 0)
-		seedrand();
+		randomread((void*)&randn, sizeof(randn));
 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
-	return (randn>>16) % n;
+	return randn;
 }
 
 int
-rand(void)
+nrand(int n)
 {
-	nrand(1);
-	return randn;
+	rand();
+	return (randn>>16) % n;
 }
 
 static uvlong uvorder = 0x0001020304050607ULL;
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -126,6 +126,7 @@
 char*		getconfenv(void);
 long		hostdomainwrite(char*, int);
 long		hostownerwrite(char*, int);
+void 		(*hwrandbuf)(void*, ulong);
 void		hzsched(void);
 Block*		iallocb(int);
 void		iallocsummary(void);
--- a/sys/src/9/port/random.c
+++ b/sys/src/9/port/random.c
@@ -5,135 +5,103 @@
 #include	"fns.h"
 #include	"../port/error.h"
 
-struct Rb
+#include	<libsec.h>
+
+/* machine specific hardware random number generator */
+void (*hwrandbuf)(void*, ulong) = nil;
+
+static struct
 {
 	QLock;
-	Rendez	producer;
-	Rendez	consumer;
-	ulong	randomcount;
-	uchar	buf[128];
-	uchar	*ep;
-	uchar	*rp;
-	uchar	*wp;
-	uchar	next;
-	uchar	wakeme;
-	ushort	bits;
-	ulong	randn;
-} rb;
+	Chachastate;
+} *rs;
 
-static int
-rbnotfull(void*)
+typedef struct Seedbuf Seedbuf;
+struct Seedbuf
 {
-	int i;
+	ulong		randomcount;
+	uchar		buf[64];
+	uchar		nbuf;
+	uchar		next;
+	ushort		bits;
 
-	i = rb.rp - rb.wp;
-	return i != 1 && i != (1 - sizeof(rb.buf));
-}
+	SHA2_512state	ds;
+};
 
-static int
-rbnotempty(void*)
+static void
+randomsample(Ureg*, Timer *t)
 {
-	return rb.wp != rb.rp;
+	Seedbuf *s = t->ta;
+
+	if(s->randomcount == 0 || s->nbuf >= sizeof(s->buf))
+		return;
+	s->bits = (s->bits<<2) ^ s->randomcount;
+	s->randomcount = 0;
+	if(++s->next < 8/2)
+		return;
+	s->next = 0;
+	s->buf[s->nbuf++] ^= s->bits;
 }
 
 static void
-genrandom(void*)
+randomseed(void*)
 {
-	up->basepri = PriNormal;
-	up->priority = up->basepri;
+	Seedbuf *s;
 
-	while(waserror())
-		;
-	for(;;){
-		if(++rb.randomcount <= 100000)
+	s = secalloc(sizeof(Seedbuf));
+
+	if(hwrandbuf != nil)
+		(*hwrandbuf)(s->buf, sizeof(s->buf));
+
+	/* Frequency close but not equal to HZ */
+	up->tns = (vlong)(MS2HZ+3)*1000000LL;
+	up->tmode = Tperiodic;
+	up->tt = nil;
+	up->ta = s;
+	up->tf = randomsample;
+	timeradd(up);
+	while(s->nbuf < sizeof(s->buf)){
+		if(++s->randomcount <= 100000)
 			continue;
 		if(anyhigher())
 			sched();
-		if(!rbnotfull(0))
-			sleep(&rb.producer, rbnotfull, 0);
 	}
-}
+	timerdel(up);
 
-/*
- *  produce random bits in a circular buffer
- */
-static void
-randomclock(void)
-{
-	if(rb.randomcount == 0 || !rbnotfull(0))
-		return;
+	sha2_512(s->buf, sizeof(s->buf), s->buf, &s->ds);
+	setupChachastate(rs, s->buf, 32, s->buf+32, 12, 20);
+	qunlock(rs);
 
-	rb.bits = (rb.bits<<2) ^ rb.randomcount;
-	rb.randomcount = 0;
+	secfree(s);
 
-	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);
+	pexit("", 1);
 }
 
 void
 randominit(void)
 {
-	/* Frequency close but not equal to HZ */
-	addclock0link(randomclock, MS2HZ+3);
-	rb.ep = rb.buf + sizeof(rb.buf);
-	rb.rp = rb.wp = rb.buf;
-	kproc("genrandom", genrandom, 0);
+	rs = secalloc(sizeof(*rs));
+	qlock(rs);	/* randomseed() unlocks once seeded */
+	kproc("randomseed", randomseed, nil);
 }
 
-/*
- *  consume random bytes from a circular buffer
- */
 ulong
 randomread(void *xp, ulong n)
 {
-	uchar *e, *p;
-	ulong x;
+	if(n == 0)
+		return 0;
 
-	p = xp;
+	if(hwrandbuf != nil)
+		(*hwrandbuf)(xp, n);
 
 	if(waserror()){
-		qunlock(&rb);
+		qunlock(rs);
 		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);
+	qlock(rs);
+	chacha_encrypt((uchar*)xp, n, rs);
+	qunlock(rs);
 	poperror();
-
-	wakeup(&rb.producer);
 
 	return n;
 }