git: 9front

Download patch

ref: f20373b1bf87d26f1f261ac968f8760c51f37df0
parent: c0371f6c589f18cf9a9ccfe11332732e7c057aac
author: jpathy <jpathy@mail.nanosouffle.net>
date: Wed May 8 19:27:58 EDT 2013

Add RDRAND Support for /dev/random

--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -299,6 +299,7 @@
 	Mmx	= 1<<23,
 	Sse	= 1<<25,	/* thus sfence instr. */
 	Sse2	= 1<<26,	/* thus mfence & lfence instr.s */
+	Rdrnd	= 1<<30,	/* RDRAND support bit */
 };
 
 /*
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -181,6 +181,7 @@
 void	wbinvd(void);
 int	wrmsr(int, vlong);
 int	xchgw(ushort*, int);
+void	rdrandbuf(void*, ulong);
 
 #define	userureg(ur)	(((ur)->cs & 3) == 3)
 #define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
--- a/sys/src/9/pc/l.s
+++ b/sys/src/9/pc/l.s
@@ -881,6 +881,38 @@
 _mwaitdone:
 	RET
 
+#define RDRANDAX	BYTE $0x0f; BYTE $0xc7; BYTE $0xf0
+
+TEXT rdrand32(SB), $-4
+_rloop32:
+	RDRANDAX
+	JCC	_rloop32
+	RET
+
+TEXT rdrandbuf(SB), $0
+	MOVL	buf+0(FP), DI
+	MOVL	cnt+4(FP), CX
+	CLD
+	MOVL	CX, DX
+	SHRL	$2, CX
+	CMPL	CX, $0
+	JE	_rndleft
+_rnddwords:
+	CALL	rdrand32(SB)
+	STOSL
+	LOOP _rnddwords
+_rndleft:
+	MOVL	DX, CX
+	ANDL	$3, CX
+	CMPL	CX, $0
+	JE	_rnddone
+_rndbytes:
+	CALL rdrand32(SB)
+	STOSB
+	LOOP _rndbytes
+_rnddone:
+	RET
+	
 /*
  * Interrupt/exception handling.
  * Each entry in the vector table calls either _strayintr or _strayintrx depending
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -41,7 +41,7 @@
 	taslock.$O\
 	tod.$O\
 	xalloc.$O\
-	random.$O\
+	pcrandom.$O\
 
 OBJ=\
 	l.$O\
--- /dev/null
+++ b/sys/src/9/pc/pcrandom.c
@@ -1,0 +1,151 @@
+#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;
+
+	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);
+}
+
+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;
+}
--