diff options
author | jpathy <jpathy@mail.nanosouffle.net> | 2013-05-08 23:27:58 +0530 |
---|---|---|
committer | jpathy <jpathy@mail.nanosouffle.net> | 2013-05-08 23:27:58 +0530 |
commit | e3883b050e1784f97bd6474c6af73023fe3bbe44 (patch) | |
tree | d1a49c51668bbab97194d67ae1f10b31be9efae8 /sys/src | |
parent | cd66b11f67654edfa54cab05422310d5c923784a (diff) |
Add RDRAND Support for /dev/random
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/9/pc/dat.h | 1 | ||||
-rw-r--r-- | sys/src/9/pc/fns.h | 1 | ||||
-rw-r--r-- | sys/src/9/pc/l.s | 32 | ||||
-rw-r--r-- | sys/src/9/pc/mkfile | 2 | ||||
-rw-r--r-- | sys/src/9/pc/pcrandom.c | 151 |
5 files changed, 186 insertions, 1 deletions
diff --git a/sys/src/9/pc/dat.h b/sys/src/9/pc/dat.h index caf2e0770..c55b35e35 100644 --- a/sys/src/9/pc/dat.h +++ b/sys/src/9/pc/dat.h @@ -299,6 +299,7 @@ enum { Mmx = 1<<23, Sse = 1<<25, /* thus sfence instr. */ Sse2 = 1<<26, /* thus mfence & lfence instr.s */ + Rdrnd = 1<<30, /* RDRAND support bit */ }; /* diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h index dca0cc614..010025f5a 100644 --- a/sys/src/9/pc/fns.h +++ b/sys/src/9/pc/fns.h @@ -181,6 +181,7 @@ void vunmap(void*, int); 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])) diff --git a/sys/src/9/pc/l.s b/sys/src/9/pc/l.s index 61394e6fb..418570e88 100644 --- a/sys/src/9/pc/l.s +++ b/sys/src/9/pc/l.s @@ -881,6 +881,38 @@ TEXT mwait(SB), $0 _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 diff --git a/sys/src/9/pc/mkfile b/sys/src/9/pc/mkfile index 5b68b85a2..5298ed0d4 100644 --- a/sys/src/9/pc/mkfile +++ b/sys/src/9/pc/mkfile @@ -41,7 +41,7 @@ PORT=\ taslock.$O\ tod.$O\ xalloc.$O\ - random.$O\ + pcrandom.$O\ OBJ=\ l.$O\ diff --git a/sys/src/9/pc/pcrandom.c b/sys/src/9/pc/pcrandom.c new file mode 100644 index 000000000..db77fbbdd --- /dev/null +++ b/sys/src/9/pc/pcrandom.c @@ -0,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; +} |