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;
+}
--
⑨