Add a random device; remove old genrandom junk; remove random from #cons
authorRonald G. Minnich <rminnich@gmail.com>
Thu, 4 Feb 2016 03:09:02 +0000 (19:09 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 4 Feb 2016 19:56:13 +0000 (14:56 -0500)
Compiles just fine.

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/dev/Kbuild
kern/drivers/dev/cons.c
kern/drivers/dev/random.c [new file with mode: 0644]
kern/include/ns.h
kern/src/ns/Kbuild
kern/src/ns/random.c [deleted file]

index 214100e..9d5d219 100644 (file)
@@ -9,6 +9,7 @@ obj-y                                           += mnt.o
 #obj-y                                         += pci.o
 obj-y                                          += pipe.o
 obj-y                                          += proc.o
+obj-y                                          += random.o
 obj-$(CONFIG_REGRESS)                          += regress.o
 obj-y                                          += root.o
 obj-y                                          += srv.o
index 99bf93b..f1dc09d 100644 (file)
@@ -84,7 +84,6 @@ static struct {
 char *sysname;
 int64_t fasthz;
 
-static void seedrand(void);
 static int readtime(uint32_t, char *, int);
 static int readbintime(char *, int);
 static int writetime(char *, int);
@@ -599,14 +598,12 @@ enum {
        Qpgrpid,
        Qpid,
        Qppid,
-       Qrandom,
        Qreboot,
        Qswap,
        Qsysctl,
        Qsysname,
        Qsysstat,
        Qtime,
-       Qurandom,
        Quser,
        Qvmctl,
        Qzero,
@@ -635,14 +632,12 @@ static struct dirtab consdir[] = {
        {"pgrpid", {Qpgrpid}, NUMSIZE, 0444},
        {"pid", {Qpid}, NUMSIZE, 0444},
        {"ppid", {Qppid}, NUMSIZE, 0444},
-       {"random", {Qrandom}, 0, 0444},
        {"reboot", {Qreboot}, 0, 0660},
        {"swap", {Qswap}, 0, 0664},
        {"sysctl", {Qsysctl}, 0, 0666},
        {"sysname", {Qsysname}, 0, 0664},
        {"sysstat", {Qsysstat}, 0, 0666},
        {"time", {Qtime}, NUMSIZE + 3 * VLNUMSIZE, 0664},
-       {"urandom", {Qurandom}, 0, 0444},
        {"user", {Quser}, 0, 0666},
        {"vmctl", {Qvmctl}, 0, 0666},
        {"zero", {Qzero}, 0, 0444},
@@ -680,7 +675,6 @@ static void consinit(void)
 #if 0
        todinit();
 #endif
-       randominit();
        /*
         * at 115200 baud, the 1024 char buffer takes 56 ms to process,
         * processing it every 22 ms should be fine
@@ -964,10 +958,6 @@ static long consread(struct chan *c, void *buf, long n, int64_t off)
                                return 0;
                        return consreadstr((uint32_t) offset, buf, n, sysname);
 
-               case Qrandom:
-               case Qurandom:
-                       return randomread(buf, n);
-
                case Qdrivers:
                        b = kzmalloc(READSTR, 0);
                        if (b == NULL)
@@ -1233,31 +1223,6 @@ static char *devname(void)
        return consdevtab.name;
 }
 
-static uint32_t randn;
-
-static void seedrand(void)
-{
-       ERRSTACK(2);
-       if (!waserror()) {
-               randomread((void *)&randn, sizeof(randn));
-               poperror();
-       }
-}
-
-int nrand(int n)
-{
-       if (randn == 0)
-               seedrand();
-       randn = randn * 1103515245 + 12345 + read_tsc();
-       return (randn >> 16) % n;
-}
-
-int rand(void)
-{
-       nrand(1);
-       return randn;
-}
-
 static uint64_t uvorder = 0x0001020304050607ULL;
 
 static uint8_t *le2int64_t(int64_t * to, uint8_t * f)
diff --git a/kern/drivers/dev/random.c b/kern/drivers/dev/random.c
new file mode 100644 (file)
index 0000000..4e54c03
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * This file is part of the UCB release of Plan 9. It is subject to the license
+ * terms in the LICENSE file found in the top-level directory of this
+ * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
+ * part of the UCB release of Plan 9, including this file, may be copied,
+ * modified, propagated, or distributed except according to the terms contained
+ * in the LICENSE file.
+ */
+
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+#include <random/fortuna.h>
+
+static qlock_t rl;
+
+/*
+ * Add entropy. This is not currently used but we might want to hook it into a
+ * hardware entropy source.
+ */
+void random_add(void *xp)
+{
+       ERRSTACK(1);
+
+       qlock(&rl);
+       if (waserror()) {
+               qunlock(&rl);
+               nexterror();
+       }
+
+       fortuna_add_entropy(xp, sizeof(xp));
+       qunlock(&rl);
+
+       poperror();
+}
+
+/*
+ *  consume random bytes
+ */
+static uint32_t _randomread(void *xp, uint32_t n)
+{
+       ERRSTACK(1);
+
+       qlock(&rl);
+
+       if (waserror()) {
+               qunlock(&rl);
+               nexterror();
+       }
+
+       fortuna_get_bytes(n, xp);
+       qunlock(&rl);
+
+       poperror();
+
+       return n;
+}
+
+/**
+ * Fast random generator
+ **/
+uint32_t urandomread(void *xp, uint32_t n)
+{
+       ERRSTACK(1);
+       uint64_t seed[16];
+       uint8_t *e, *p;
+       uint32_t x = 0;
+       uint64_t s0;
+       uint64_t s1;
+
+       // The initial seed is from a good random pool.
+       _randomread(seed, sizeof(seed));
+       p = xp;
+       for (e = p + n; p < e;) {
+               s0 = seed[x];
+               s1 = seed[x = (x + 1) & 15];
+               s1 ^= s1 << 31;
+               s1 ^= s1 >> 11;
+               s0 ^= s0 >> 30;
+               *p++ = (seed[x] = s0 ^ s1) * 1181783497276652981LL;
+       }
+
+       return n;
+}
+
+struct dev randomdevtab;
+
+static char *devname(void)
+{
+       return randomdevtab.name;
+}
+
+enum {
+       Qdir,
+       Qrandom,
+       Qurandom
+};
+
+static
+struct dirtab randomdir[] = {
+       {".", {Qdir, 0, QTDIR}, 0, DMDIR | 0500},
+       {"random", {Qrandom}, 0, 0444},
+       {"urandom", {Qurandom}, 0, 0444},
+};
+
+static void randominit(void)
+{
+       qlock_init(&rl);
+}
+
+/*
+ *  create a random, no streams are created until an open
+ */
+static struct chan *randomattach(char *spec)
+{
+       return devattach(devname(), spec);
+}
+
+static struct walkqid *randomwalk(struct chan *c, struct chan *nc, char **name,
+                                                               int nname)
+{
+       return devwalk(c, nc, name, nname, randomdir,
+                      ARRAY_SIZE(randomdir), devgen);
+}
+
+static int randomstat(struct chan *c, uint8_t *dp, int n)
+{
+       return devstat(c, dp, n, randomdir, ARRAY_SIZE(randomdir), devgen);
+}
+
+/*
+ *  if the stream doesn't exist, create it
+ */
+static struct chan *randomopen(struct chan *c, int omode)
+{
+       return devopen(c, omode, randomdir, ARRAY_SIZE(randomdir), devgen);
+}
+
+static void randomclose(struct chan *c)
+{
+}
+
+static long randomread(struct chan *c, void *va, long n, int64_t ignored)
+{
+       switch (c->qid.path) {
+               case Qdir:
+                       return devdirread(c, va, n, randomdir,
+                                         ARRAY_SIZE(randomdir), devgen);
+               case Qrandom:
+                       return _randomread(va, n);
+               case Qurandom:
+                       return urandomread(va, n);
+               default:
+                       panic("randomread: qid %d is impossible", c->qid.path);
+       }
+       return -1;      /* not reached */
+}
+
+/*
+ *  A write to a closed random causes an ERANDOM error to be thrown.
+ */
+static long randomwrite(struct chan *c, void *va, long n, int64_t ignored)
+{
+       error(EPERM, "No use for writing random just yet");
+       return -1;
+}
+
+static long randombwrite(struct chan *c, struct block *bp, uint32_t junk)
+{
+       error(EPERM, "No use for writing random just yet");
+       return -1;
+}
+
+static int randomwstat(struct chan *c, uint8_t *dp, int n)
+{
+       error(EPERM, "No use for wstat random just yet");
+       return -1;
+}
+
+struct dev randomdevtab __devtab = {
+       .name = "random",
+
+       .reset = devreset,
+       .init = randominit,
+       .shutdown = devshutdown,
+       .attach = randomattach,
+       .walk = randomwalk,
+       .stat = randomstat,
+       .open = randomopen,
+       .create = devcreate,
+       .close = randomclose,
+       .read = randomread,
+       .write = randomwrite,
+       .remove = devremove,
+       .wstat = randomwstat,
+       .power = devpower,
+       .chaninfo = devchaninfo,
+};
+
+/* This is something used by the TCP stack.
+ * I have no idea of why these numbers were chosen. */
+static uint32_t randn;
+
+static void seedrand(void)
+{
+       ERRSTACK(2);
+       if (!waserror()) {
+               _randomread((void *)&randn, sizeof(randn));
+               poperror();
+       }
+}
+
+int nrand(int n)
+{
+       if (randn == 0)
+               seedrand();
+       randn = randn * 1103515245 + 12345 + read_tsc();
+       return (randn >> 16) % n;
+}
+
index c24f4c8..c0e715f 100644 (file)
@@ -847,8 +847,6 @@ int qwrite(struct queue *, void *, int);
 typedef void (*qio_wake_cb_t)(struct queue *q, void *data, int filter);
 void qio_set_wake_cb(struct queue *q, qio_wake_cb_t func, void *data);
 
-void randominit(void);
-uint32_t randomread(void *, uint32_t);
 void *realloc(void *, uint32_t);
 int readmem(unsigned long offset, char *buf, unsigned long n,
                        void *mem, size_t mem_len);
index 17f40b8..32fef4d 100644 (file)
@@ -13,7 +13,6 @@ obj-y                                         += getfields.o
 obj-y                                          += parse.o
 obj-y                                          += pgrp.o
 obj-y                                          += qio.o
-obj-y                                          += random.o
 obj-y                                          += sysfile.o
 obj-y                                          += tokenize.o
 obj-y                                          += util.o
diff --git a/kern/src/ns/random.c b/kern/src/ns/random.c
deleted file mode 100644 (file)
index 76cbfc4..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
- * Portions Copyright © 1997-1999 Vita Nuova Limited
- * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
- *                                (www.vitanuova.com)
- * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
- *
- * Modified for the Akaros operating system:
- * Copyright (c) 2013-2014 The Regents of the University of California
- * Copyright (c) 2013-2015 Google Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE. */
-
-#include <vfs.h>
-#include <kfs.h>
-#include <slab.h>
-#include <kmalloc.h>
-#include <kref.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <error.h>
-#include <cpio.h>
-#include <pmap.h>
-#include <smp.h>
-#include <apipe.h>
-
-#define RAND_BUF_SZ 1024
-
-static struct rb {
-       uint8_t buf[RAND_BUF_SZ];
-       struct atomic_pipe ap;
-} rb;
-
-/* The old style seemed to have genrandom incrementing a shared mem variable,
- * randomcount, while randomclock, sort of an interrupt handler, would use this
- * variable to generate random numbers.  They needed to run concurrently to get
- * some sort of randonmess.  To do so, randomclock wouldn't run if genrandom
- * wasn't in the process of incrementing the variable.  So we'd need genrandom
- * working (in the background, but that doesn't work so well for us), when the
- * randomclock alarm fired.  Then we could get 2 bits.  We'd do that 4 times
- * to make our random byte.
- *
- * In akaros, genrandom would spin to 100,000 every time, without interruption,
- * since the randomcount's alarm wouldn't interrupt: they are both routine
- * kernel messages.  So we might as well just call kthread yield each time.
- * Even then, it was still really slow.  This was because we only got 2 bits of
- * randomness every 13ms (randomcount would make 2 bits per run, it would run
- * once every 13ms, unless I screwed up the math on that.  It was supposed to
- * run with a "Frequency close but not equal to HZ").
- *
- * We'd also use the old random values in the ring buffer to muck with the
- * randomness. */
-static void genrandom(void *unused)
-{
-       uint8_t rand_two_bits, rp_byte, wp_byte;
-       uint8_t rand_byte = 0;
-       unsigned int mod_four = 0;
-       //setpri(PriBackground);
-
-       for (;;) {
-               /* this seems just as good (or bad) as the old genrandom incrementing a
-                * shared memory variable concurrently */
-               rand_two_bits = read_tsc() & 0x3;
-               rand_byte = (rand_byte << 2) ^ rand_two_bits;
-
-               /* put in a kthread_yield or something here, if we want to replicate the
-                * way randomclock would return, waiting til its next tick to get two
-                * more bits. */
-
-               /* every four times, we built a full random byte */
-               if (++mod_four % 4 == 0)
-                       continue;
-
-               /* the old plan9 generator would xor our rand_byte with both the value
-                * of the read pointer and the write pointer:
-                *      *rb.wp ^= rb.bits ^ *rb.rp;
-                * we'll peak into the apipe to do the same */
-               rp_byte = rb.buf[rb.ap.ap_rd_off & (RAND_BUF_SZ - 1)];
-               wp_byte = rb.buf[rb.ap.ap_wr_off & (RAND_BUF_SZ - 1)];
-               rand_byte ^= rp_byte ^ wp_byte;
-               apipe_write(&rb.ap, &rand_byte, 1);
-       }
-}
-
-void randominit(void)
-{
-       apipe_init(&rb.ap, rb.buf, sizeof(rb.buf), 1);
-       ktask("genrandom", genrandom, 0);
-}
-
-uint32_t randomread(void *buf, uint32_t n)
-{
-       int amt;
-       uint32_t ret = 0;
-
-       for (int i = 0; i < n; i++) {
-               /* read the random byte directly into the (user) buffer */
-               amt = apipe_read(&rb.ap, buf, 1);
-               if (amt < 0)
-                       error(EFAIL, "randomread apipe");
-               if (amt != 1)
-                       warn("Odd amount read from random apipe");
-               buf++;
-               ret += amt;
-       }
-       return ret;
-}