Add the Inferno license to files we got from Inferno
[akaros.git] / kern / src / ns / random.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <kfs.h>
31 #include <slab.h>
32 #include <kmalloc.h>
33 #include <kref.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <assert.h>
37 #include <error.h>
38 #include <cpio.h>
39 #include <pmap.h>
40 #include <smp.h>
41 #include <apipe.h>
42
43 #define RAND_BUF_SZ 1024
44
45 static struct rb {
46         uint8_t buf[RAND_BUF_SZ];
47         struct atomic_pipe ap;
48 } rb;
49
50 /* The old style seemed to have genrandom incrementing a shared mem variable,
51  * randomcount, while randomclock, sort of an interrupt handler, would use this
52  * variable to generate random numbers.  They needed to run concurrently to get
53  * some sort of randonmess.  To do so, randomclock wouldn't run if genrandom
54  * wasn't in the process of incrementing the variable.  So we'd need genrandom
55  * working (in the background, but that doesn't work so well for us), when the
56  * randomclock alarm fired.  Then we could get 2 bits.  We'd do that 4 times
57  * to make our random byte.
58  *
59  * In akaros, genrandom would spin to 100,000 every time, without interruption,
60  * since the randomcount's alarm wouldn't interrupt: they are both routine
61  * kernel messages.  So we might as well just call kthread yield each time.
62  * Even then, it was still really slow.  This was because we only got 2 bits of
63  * randomness every 13ms (randomcount would make 2 bits per run, it would run
64  * once every 13ms, unless I screwed up the math on that.  It was supposed to
65  * run with a "Frequency close but not equal to HZ").
66  *
67  * We'd also use the old random values in the ring buffer to muck with the
68  * randomness. */
69 static void genrandom(void *unused)
70 {
71         uint8_t rand_two_bits, rp_byte, wp_byte;
72         uint8_t rand_byte = 0;
73         unsigned int mod_four = 0;
74         //setpri(PriBackground);
75
76         for (;;) {
77                 /* this seems just as good (or bad) as the old genrandom incrementing a
78                  * shared memory variable concurrently */
79                 rand_two_bits = read_tsc() & 0x3;
80                 rand_byte = (rand_byte << 2) ^ rand_two_bits;
81
82                 /* put in a kthread_yield or something here, if we want to replicate the
83                  * way randomclock would return, waiting til its next tick to get two
84                  * more bits. */
85
86                 /* every four times, we built a full random byte */
87                 if (++mod_four % 4 == 0)
88                         continue;
89
90                 /* the old plan9 generator would xor our rand_byte with both the value
91                  * of the read pointer and the write pointer:
92                  *      *rb.wp ^= rb.bits ^ *rb.rp;
93                  * we'll peak into the apipe to do the same */
94                 rp_byte = rb.buf[rb.ap.ap_rd_off & (RAND_BUF_SZ - 1)];
95                 wp_byte = rb.buf[rb.ap.ap_wr_off & (RAND_BUF_SZ - 1)];
96                 rand_byte ^= rp_byte ^ wp_byte;
97                 apipe_write(&rb.ap, &rand_byte, 1);
98         }
99 }
100
101 void randominit(void)
102 {
103         apipe_init(&rb.ap, rb.buf, sizeof(rb.buf), 1);
104         ktask("genrandom", genrandom, 0);
105 }
106
107 uint32_t randomread(void *buf, uint32_t n)
108 {
109         int amt;
110         uint32_t ret = 0;
111
112         for (int i = 0; i < n; i++) {
113                 /* read the random byte directly into the (user) buffer */
114                 amt = apipe_read(&rb.ap, buf, 1);
115                 if (amt < 0)
116                         error(EFAIL, "randomread apipe");
117                 if (amt != 1)
118                         warn("Odd amount read from random apipe");
119                 buf++;
120                 ret += amt;
121         }
122         return ret;
123 }