1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 struct Rb
8 {
9 QLock;
10 Rendez producer;
11 Rendez consumer;
12 ulong randomcount;
13 uchar buf[1024];
14 uchar *ep;
15 uchar *rp;
16 uchar *wp;
17 uchar next;
18 uchar wakeme;
19 ushort bits;
20 ulong randn;
21 } rb;
22
23 static int
rbnotfull(void *)24 rbnotfull(void*)
25 {
26 int i;
27
28 i = rb.rp - rb.wp;
29 return i != 1 && i != (1 - sizeof(rb.buf));
30 }
31
32 static int
rbnotempty(void *)33 rbnotempty(void*)
34 {
35 return rb.wp != rb.rp;
36 }
37
38 static void
genrandom(void *)39 genrandom(void*)
40 {
41 up->basepri = PriNormal;
42 up->priority = up->basepri;
43
44 for(;;){
45 for(;;)
46 if(++rb.randomcount > 100000)
47 break;
48 if(anyhigher())
49 sched();
50 if(!rbnotfull(0))
51 sleep(&rb.producer, rbnotfull, 0);
52 }
53 }
54
55 /*
56 * produce random bits in a circular buffer
57 */
58 static void
randomclock(void)59 randomclock(void)
60 {
61 if(rb.randomcount == 0 || !rbnotfull(0))
62 return;
63
64 rb.bits = (rb.bits<<2) ^ rb.randomcount;
65 rb.randomcount = 0;
66
67 rb.next++;
68 if(rb.next != 8/2)
69 return;
70 rb.next = 0;
71
72 *rb.wp ^= rb.bits;
73 if(rb.wp+1 == rb.ep)
74 rb.wp = rb.buf;
75 else
76 rb.wp = rb.wp+1;
77
78 if(rb.wakeme)
79 wakeup(&rb.consumer);
80 }
81
82 void
randominit(void)83 randominit(void)
84 {
85 /* Frequency close but not equal to HZ */
86 addclock0link(randomclock, 13);
87 rb.ep = rb.buf + sizeof(rb.buf);
88 rb.rp = rb.wp = rb.buf;
89 kproc("genrandom", genrandom, 0);
90 }
91
92 /*
93 * consume random bytes from a circular buffer
94 */
95 ulong
randomread(void * xp,ulong n)96 randomread(void *xp, ulong n)
97 {
98 uchar *e, *p;
99 ulong x;
100
101 p = xp;
102
103 if(waserror()){
104 qunlock(&rb);
105 nexterror();
106 }
107
108 qlock(&rb);
109 for(e = p + n; p < e; ){
110 if(rb.wp == rb.rp){
111 rb.wakeme = 1;
112 wakeup(&rb.producer);
113 sleep(&rb.consumer, rbnotempty, 0);
114 rb.wakeme = 0;
115 continue;
116 }
117
118 /*
119 * beating clocks will be predictable if
120 * they are synchronized. Use a cheap pseudo-
121 * random number generator to obscure any cycles.
122 */
123 x = rb.randn*1103515245 ^ *rb.rp;
124 *p++ = rb.randn = x;
125
126 if(rb.rp+1 == rb.ep)
127 rb.rp = rb.buf;
128 else
129 rb.rp = rb.rp+1;
130 }
131 qunlock(&rb);
132 poperror();
133
134 wakeup(&rb.producer);
135
136 return n;
137 }
138