Thu Jun 13 00:55:01 2013 UTC ()
Convert the entropy pool framework from pseudo-callout-driven to
soft interrupt driven operation.
Add a polling mode of operation -- now we can ask hardware random number
generators to top us up just when we need it (bcm2835_rng and amdpm
converted as examples).
Fix a stall noticed with repeated reads from /dev/random while testing.
(tls)
diff -r1.3 -r1.4 src/sys/arch/arm/broadcom/bcm2835_rng.c
diff -r1.11 -r1.12 src/sys/dev/rndpseudo.c
diff -r1.36 -r1.37 src/sys/dev/pci/amdpm.c
diff -r1.19 -r1.20 src/sys/dev/pci/amdpm_smbus.c
diff -r1.9 -r1.10 src/sys/dev/pci/amdpmvar.h
diff -r1.9 -r1.10 src/sys/dev/pci/hifn7751var.h
diff -r1.51 -r1.52 src/sys/dev/pci/hifn7751.c
diff -r1.28 -r1.29 src/sys/dev/pci/ubsec.c
diff -r1.4 -r1.5 src/sys/dev/pci/ubsecvar.h
diff -r1.300 -r1.301 src/sys/dev/scsipi/sd.c
diff -r1.2 -r1.3 src/sys/kern/kern_rndpool.c
diff -r1.10 -r1.11 src/sys/kern/kern_rndq.c
diff -r1.16 -r1.17 src/sys/kern/subr_cprng.c
diff -r1.35 -r1.36 src/sys/sys/rnd.h
--- src/sys/arch/arm/broadcom/bcm2835_rng.c 2013/02/01 16:10:16 1.3
+++ src/sys/arch/arm/broadcom/bcm2835_rng.c 2013/06/13 00:55:01 1.4
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835_rng.c,v 1.3 2013/02/01 16:10:16 skrll Exp $ */
+/* $NetBSD: bcm2835_rng.c,v 1.4 2013/06/13 00:55:01 tls Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_rng.c,v 1.3 2013/02/01 16:10:16 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_rng.c,v 1.4 2013/06/13 00:55:01 tls Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -38,6 +38,7 @@
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/rnd.h>
+#include <sys/atomic.h>
#include <arm/broadcom/bcm_amba.h>
#include <arm/broadcom/bcm2835reg.h>
@@ -59,16 +60,16 @@
bus_space_handle_t sc_ioh;
krndsource_t sc_rnd;
- callout_t sc_tick;
+ kmutex_t sc_mutex;
+
uint32_t sc_data[RNG_DATA_MAX];
};
+static void bcmrng_get(size_t, void *);
static int bcmrng_match(device_t, cfdata_t, void *);
static void bcmrng_attach(device_t, device_t, void *);
-static void bcmrng_tick(void *);
-
CFATTACH_DECL_NEW(bcmrng_amba, sizeof(struct bcm2835rng_softc),
bcmrng_match, bcmrng_attach, NULL, NULL);
@@ -103,12 +104,12 @@
return;
}
+ mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
+
+ rndsource_setcb(&sc->sc_rnd, bcmrng_get, sc);
rnd_attach_source(&sc->sc_rnd, device_xname(self), RND_TYPE_RNG,
- RND_FLAG_NO_ESTIMATE);
+ RND_FLAG_NO_ESTIMATE|RND_FLAG_HASCB);
- callout_init(&sc->sc_tick, CALLOUT_MPSAFE);
- callout_setfunc(&sc->sc_tick, bcmrng_tick, sc);
-
/* discard initial numbers, broadcom says they are "less random" */
bus_space_write_4(sc->sc_iot, sc->sc_ioh, RNG_STATUS, 0x40000);
@@ -116,26 +117,34 @@
ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RNG_CTRL);
ctrl |= RNG_CTRL_EN;
bus_space_write_4(sc->sc_iot, sc->sc_ioh, RNG_CTRL, ctrl);
-
- /* start timer */
- bcmrng_tick(sc);
}
static void
-bcmrng_tick(void *priv)
+bcmrng_get(size_t bytes, void *priv)
{
- struct bcm2835rng_softc *sc = priv;
+ struct bcm2835rng_softc *sc = priv;
uint32_t status;
- int cnt;
+ int need = bytes, cnt;
- status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RNG_STATUS);
- cnt = (status & RNG_STATUS_CNT_MASK) >> RNG_STATUS_CNT_SHIFT;
- if (cnt > 0) {
- bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh, RNG_DATA,
- sc->sc_data, cnt);
- rnd_add_data(&sc->sc_rnd, sc->sc_data,
- cnt * 4, cnt * 4 * NBBY);
+ mutex_spin_enter(&sc->sc_mutex);
+
+ printf("bcmrng: asked for %d bytes", (int)bytes);
+
+ if (__predict_false(need < 1)) {
+ return;
}
- callout_schedule(&sc->sc_tick, 1);
+ while (need > 0) {
+ status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RNG_STATUS);
+ cnt = (status & RNG_STATUS_CNT_MASK) >> RNG_STATUS_CNT_SHIFT;
+ if (cnt > 0) {
+ bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh,
+ RNG_DATA, sc->sc_data, cnt);
+ rnd_add_data(&sc->sc_rnd, sc->sc_data,
+ cnt * 4, cnt * 4 * NBBY);
+ }
+
+ need -= cnt * 4;
+ }
+ mutex_spin_exit(&sc->sc_mutex);
}
--- src/sys/dev/Attic/rndpseudo.c 2012/11/25 15:29:24 1.11
+++ src/sys/dev/Attic/rndpseudo.c 2013/06/13 00:55:01 1.12
@@ -1,4 +1,4 @@
-/* $NetBSD: rndpseudo.c,v 1.11 2012/11/25 15:29:24 christos Exp $ */
+/* $NetBSD: rndpseudo.c,v 1.12 2013/06/13 00:55:01 tls Exp $ */
/*-
* Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.11 2012/11/25 15:29:24 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.12 2013/06/13 00:55:01 tls Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@@ -219,6 +219,7 @@
}
ctx->cprng = NULL;
ctx->hard = hard;
+ ctx->bytesonkey = 0;
mutex_init(&ctx->interlock, MUTEX_DEFAULT, IPL_NONE);
return fd_clone(fp, fd, flag, &rnd_fileops, ctx);
@@ -298,12 +299,19 @@
/* XXX is this _really_ what's wanted? */
if (ctx->hard) {
+#ifdef RND_VERBOSE
+ printf("rnd: hard, want = %d, strength = %d, "
+ "bytesonkey = %d\n", (int)want, (int)strength,
+ (int)ctx->bytesonkey);
+#endif
n = MIN(want, strength - ctx->bytesonkey);
if (n < 1) {
- cprng_strong_deplete(cprng);
- n = MIN(want, strength);
- ctx->bytesonkey = 0;
- membar_producer();
+#ifdef RND_VERBOSE
+ printf("rnd: BAD BAD BAD: n = %d, want = %d, "
+ "strength = %d, bytesonkey = %d\n", n,
+ (int)want, (int)strength,
+ (int)ctx->bytesonkey);
+#endif
}
} else {
n = want;
@@ -313,7 +321,15 @@
(fp->f_flag & FNONBLOCK) ? FNONBLOCK : 0);
if (ctx->hard && nread > 0) {
- atomic_add_int(&ctx->bytesonkey, nread);
+ if (atomic_add_int_nv(&ctx->bytesonkey, nread) >=
+ strength) {
+ cprng_strong_deplete(cprng);
+ ctx->bytesonkey = 0;
+ membar_producer();
+ }
+#ifdef RND_VERBOSE
+ printf("rnd: new bytesonkey %d\n", ctx->bytesonkey);
+#endif
}
if (nread < 1) {
if (fp->f_flag & FNONBLOCK) {
--- src/sys/dev/pci/amdpm.c 2012/10/27 17:18:28 1.36
+++ src/sys/dev/pci/amdpm.c 2013/06/13 00:55:01 1.37
@@ -1,4 +1,4 @@
-/* $NetBSD: amdpm.c,v 1.36 2012/10/27 17:18:28 chs Exp $ */
+/* $NetBSD: amdpm.c,v 1.37 2013/06/13 00:55:01 tls Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdpm.c,v 1.36 2012/10/27 17:18:28 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdpm.c,v 1.37 2013/06/13 00:55:01 tls Exp $");
#include "opt_amdpm.h"
@@ -40,6 +40,7 @@
#include <sys/device.h>
#include <sys/callout.h>
#include <sys/rnd.h>
+#include <sys/mutex.h>
#include <sys/bus.h>
#include <dev/ic/acpipmtimer.h>
@@ -55,6 +56,7 @@
#include <dev/pci/amdpm_smbusreg.h>
static void amdpm_rnd_callout(void *);
+static void amdpm_rnd_callout_locked(void *);
#ifdef AMDPM_RND_COUNTERS
#define AMDPM_RNDCNT_INCR(ev) (ev)->ev_count++
@@ -83,6 +85,17 @@
}
static void
+amdpm_rnd_get(size_t bytes, void *priv)
+{
+ struct amdpm_softc *sc = priv;
+
+ mutex_enter(&sc->sc_mutex);
+ sc->sc_rnd_need = bytes;
+ amdpm_rnd_callout_locked(sc);
+ mutex_exit(&sc->sc_mutex);
+}
+
+static void
amdpm_attach(device_t parent, device_t self, void *aux)
{
struct amdpm_softc *sc = device_private(self);
@@ -151,6 +164,9 @@
AMDPM_TMR, ((confreg & AMDPM_TMR32) ? ACPIPMT_32BIT : 0));
}
+ /* XXX this mutex is IPL_VM because it can be taken by rnd_getmore() */
+ mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
+
/* try to attach devices on the smbus */
if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC8111_ACPI ||
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
@@ -173,7 +189,9 @@
aprint_normal_dev(self, ""
"random number generator enabled (apprx. %dms)\n",
i);
- callout_init(&sc->sc_rnd_ch, 0);
+ callout_init(&sc->sc_rnd_ch, CALLOUT_MPSAFE);
+ rndsource_setcb(&sc->sc_rnd_source,
+ amdpm_rnd_get, sc);
rnd_attach_source(&sc->sc_rnd_source,
device_xname(self), RND_TYPE_RNG,
/*
@@ -187,7 +205,7 @@
* XXX as entropy, which is not a good idea since
* XXX we add data periodically from a callout.
*/
- RND_FLAG_NO_ESTIMATE);
+ RND_FLAG_NO_ESTIMATE|RND_FLAG_HASCB);
#ifdef AMDPM_RND_COUNTERS
evcnt_attach_dynamic(&sc->sc_rnd_hits, EVCNT_TYPE_MISC,
NULL, device_xname(self), "rnd hits");
@@ -199,6 +217,7 @@
"rnd data");
}
#endif
+ sc->sc_rnd_need = RND_POOLBITS / NBBY;
amdpm_rnd_callout(sc);
}
}
@@ -208,7 +227,7 @@
amdpm_match, amdpm_attach, NULL, NULL);
static void
-amdpm_rnd_callout(void *v)
+amdpm_rnd_callout_locked(void *v)
{
struct amdpm_softc *sc = v;
u_int32_t rngreg;
@@ -216,12 +235,18 @@
int i;
#endif
+ if (sc->sc_rnd_need < 1) {
+ callout_stop(&sc->sc_rnd_ch);
+ return;
+ }
+
if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGSTAT) &
AMDPM_RNGDONE) != 0) {
rngreg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
AMDPM_RNGDATA);
rnd_add_data(&sc->sc_rnd_source, &rngreg,
sizeof(rngreg), sizeof(rngreg) * NBBY);
+ sc->sc_rnd_need -= sizeof(rngreg);
#ifdef AMDPM_RND_COUNTERS
AMDPM_RNDCNT_INCR(&sc->sc_rnd_hits);
for (i = 0; i < sizeof(rngreg); i++, rngreg >>= NBBY)
@@ -232,5 +257,17 @@
else
AMDPM_RNDCNT_INCR(&sc->sc_rnd_miss);
#endif
- callout_reset(&sc->sc_rnd_ch, 1, amdpm_rnd_callout, sc);
+ if (sc->sc_rnd_need > 0) {
+ callout_reset(&sc->sc_rnd_ch, 1, amdpm_rnd_callout, sc);
+ }
+}
+
+static void
+amdpm_rnd_callout(void *v)
+{
+ struct amdpm_softc *sc = v;
+
+ mutex_enter(&sc->sc_mutex);
+ amdpm_rnd_callout_locked(v);
+ mutex_exit(&sc->sc_mutex);
}
--- src/sys/dev/pci/amdpm_smbus.c 2012/10/27 17:18:28 1.19
+++ src/sys/dev/pci/amdpm_smbus.c 2013/06/13 00:55:01 1.20
@@ -1,4 +1,4 @@
-/* $NetBSD: amdpm_smbus.c,v 1.19 2012/10/27 17:18:28 chs Exp $ */
+/* $NetBSD: amdpm_smbus.c,v 1.20 2013/06/13 00:55:01 tls Exp $ */
/*
* Copyright (c) 2005 Anil Gopinath (anil_public@yahoo.com)
@@ -32,7 +32,7 @@
* AMD-8111 HyperTransport I/O Hub
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdpm_smbus.c,v 1.19 2012/10/27 17:18:28 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdpm_smbus.c,v 1.20 2013/06/13 00:55:01 tls Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -82,8 +82,6 @@
sc->sc_i2c.ic_read_byte = NULL;
sc->sc_i2c.ic_write_byte = NULL;
sc->sc_i2c.ic_exec = amdpm_smbus_exec;
-
- mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
iba.iba_tag = &sc->sc_i2c;
(void)config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
--- src/sys/dev/pci/amdpmvar.h 2012/10/27 17:18:28 1.9
+++ src/sys/dev/pci/amdpmvar.h 2013/06/13 00:55:01 1.10
@@ -1,4 +1,4 @@
-/* $NetBSD: amdpmvar.h,v 1.9 2012/10/27 17:18:28 chs Exp $ */
+/* $NetBSD: amdpmvar.h,v 1.10 2013/06/13 00:55:01 tls Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -53,6 +53,7 @@
struct callout sc_rnd_ch;
krndsource_t sc_rnd_source;
+ int sc_rnd_need;
#ifdef AMDPM_RND_COUNTERS
struct evcnt sc_rnd_hits;
struct evcnt sc_rnd_miss;
--- src/sys/dev/pci/hifn7751var.h 2012/10/27 17:18:32 1.9
+++ src/sys/dev/pci/hifn7751var.h 2013/06/13 00:55:01 1.10
@@ -1,4 +1,4 @@
-/* $NetBSD: hifn7751var.h,v 1.9 2012/10/27 17:18:32 chs Exp $ */
+/* $NetBSD: hifn7751var.h,v 1.10 2013/06/13 00:55:01 tls Exp $ */
/* $OpenBSD: hifn7751var.h,v 1.18 2000/06/02 22:36:45 deraadt Exp $ */
/*
@@ -169,8 +169,8 @@
struct callout sc_rngto; /* rng timeout */
struct callout sc_tickto; /* led-clear timeout */
krndsource_t sc_rnd_source;
- int sc_rngfirst;
int sc_rnghz;
+ int sc_rng_need; /* how many bytes wanted */
int sc_c_busy; /* command ring busy */
int sc_s_busy; /* source data ring busy */
int sc_d_busy; /* destination data ring busy */
@@ -184,6 +184,7 @@
pcitag_t sc_pci_tag;
bus_size_t sc_waw_lastreg;
int sc_waw_lastgroup;
+ kmutex_t sc_mtx;
};
#define WRITE_REG_0(sc,reg,val) hifn_write_4((sc), 0, (reg), (val))
--- src/sys/dev/pci/hifn7751.c 2012/10/27 17:18:32 1.51
+++ src/sys/dev/pci/hifn7751.c 2013/06/13 00:55:01 1.52
@@ -1,4 +1,4 @@
-/* $NetBSD: hifn7751.c,v 1.51 2012/10/27 17:18:32 chs Exp $ */
+/* $NetBSD: hifn7751.c,v 1.52 2013/06/13 00:55:01 tls Exp $ */
/* $FreeBSD: hifn7751.c,v 1.5.2.7 2003/10/08 23:52:00 sam Exp $ */
/* $OpenBSD: hifn7751.c,v 1.140 2003/08/01 17:55:54 deraadt Exp $ */
@@ -48,10 +48,11 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hifn7751.c,v 1.51 2012/10/27 17:18:32 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hifn7751.c,v 1.52 2013/06/13 00:55:01 tls Exp $");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/errno.h>
#include <sys/malloc.h>
@@ -140,6 +141,7 @@
struct hifn_command *);
static int hifn_init_pubrng(struct hifn_softc *);
static void hifn_rng(void *);
+static void hifn_rng_locked(void *);
static void hifn_tick(void *);
static void hifn_abort(struct hifn_softc *);
static void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *,
@@ -155,7 +157,6 @@
u_int8_t *);
#endif /* HAVE_CRYPTO_LZS */
-
struct hifn_stats hifnstats;
static const struct hifn_product {
@@ -418,14 +419,18 @@
sc->sc_dmamap->dm_mapsize,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
- if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG))
+ if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG)) {
hifn_init_pubrng(sc);
+ sc->sc_rng_need = RND_POOLBITS / NBBY;
+ }
+ mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
+
#ifdef __OpenBSD__
timeout_set(&sc->sc_tickto, hifn_tick, sc);
timeout_add(&sc->sc_tickto, hz);
#else
- callout_init(&sc->sc_tickto, 0);
+ callout_init(&sc->sc_tickto, CALLOUT_MPSAFE);
callout_reset(&sc->sc_tickto, hz, hifn_tick, sc);
#endif
return;
@@ -448,6 +453,18 @@
bus_space_unmap(sc->sc_st0, sc->sc_sh0, iosize0);
}
+static void
+hifn_rng_get(size_t bytes, void *priv)
+{
+ struct hifn_softc *sc = priv;
+
+ mutex_enter(&sc->sc_mtx);
+ sc->sc_rng_need = bytes;
+
+ hifn_rng_locked(sc);
+ mutex_exit(&sc->sc_mtx);
+}
+
static int
hifn_init_pubrng(struct hifn_softc *sc)
{
@@ -500,6 +517,7 @@
DELAY(4000);
#ifdef __NetBSD__
+ rndsource_setcb(&sc->sc_rnd_source, hifn_rng_get, sc);
/*
* XXX Careful! The use of RND_FLAG_NO_ESTIMATE
* XXX here is unobvious: we later feed raw bits
@@ -512,10 +530,10 @@
* XXX we add data periodically from a callout.
*/
rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv),
- RND_TYPE_RNG, RND_FLAG_NO_ESTIMATE);
+ RND_TYPE_RNG,
+ RND_FLAG_NO_ESTIMATE|RND_FLAG_HASCB);
#endif
- sc->sc_rngfirst = 1;
if (hz >= 100)
sc->sc_rnghz = hz / 100;
else
@@ -523,7 +541,7 @@
#ifdef __OpenBSD__
timeout_set(&sc->sc_rngto, hifn_rng, sc);
#else /* !__OpenBSD__ */
- callout_init(&sc->sc_rngto, 0);
+ callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
#endif /* !__OpenBSD__ */
}
@@ -541,7 +559,7 @@
}
static void
-hifn_rng(void *vsc)
+hifn_rng_locked(void *vsc)
{
struct hifn_softc *sc = vsc;
#ifdef __NetBSD__
@@ -551,7 +569,13 @@
#endif
uint32_t sts;
int i;
+ size_t got, gotent;
+ if (sc->sc_rng_need < 1) {
+ callout_stop(&sc->sc_rngto);
+ return;
+ }
+
if (sc->sc_flags & HIFN_IS_7811) {
for (i = 0; i < 5; i++) { /* XXX why 5? */
sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS);
@@ -569,14 +593,12 @@
*/
num[0] = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
num[1] = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
+ got = 2 * sizeof(num[0]);
+ gotent = (got * NBBY) / HIFN_RNG_BITSPER;
- if (sc->sc_rngfirst)
- sc->sc_rngfirst = 0;
#ifdef __NetBSD__
- rnd_add_data(&sc->sc_rnd_source, num,
- 2 * sizeof(num[0]),
- (2 * sizeof(num[0]) * NBBY) /
- HIFN_RNG_BITSPER);
+ rnd_add_data(&sc->sc_rnd_source, num, got, gotent);
+ sc->sc_rng_need -= gotent;
#else
/*
* XXX This is a really bad idea.
@@ -597,13 +619,16 @@
}
} else {
-#ifdef __NetBSD__
- /* First time through, try to help fill the pool. */
- int nwords = sc->sc_rngfirst ?
- sizeof(num) / sizeof(num[0]) : 4;
-#else
- int nwords = 2;
-#endif
+ int nwords = 0;
+
+ if (sc->sc_rng_need) {
+ nwords = (sc->sc_rng_need * NBBY) / HIFN_RNG_BITSPER;
+ }
+
+ if (nwords < 2) {
+ nwords = 2;
+ }
+
/*
* We must be *extremely* careful here. The Hifn
* 795x differ from the published 6500 RNG design
@@ -624,24 +649,18 @@
* read must require at least one PCI cycle, and
* RNG_Clk is at least PCI_Clk, this is safe.
*/
-
-
- if (sc->sc_rngfirst) {
- sc->sc_rngfirst = 0;
- }
-
-
for(i = 0 ; i < nwords * 8; i++)
{
volatile u_int32_t regtmp;
regtmp = READ_REG_1(sc, HIFN_1_RNG_DATA);
num[i / 8] = regtmp;
}
+
+ got = nwords * sizeof(num[0]);
+ gotent = (got * NBBY) / HIFN_RNG_BITSPER;
#ifdef __NetBSD__
- rnd_add_data(&sc->sc_rnd_source, num,
- nwords * sizeof(num[0]),
- (nwords * sizeof(num[0]) * NBBY) /
- HIFN_RNG_BITSPER);
+ rnd_add_data(&sc->sc_rnd_source, num, got, gotent);
+ sc->sc_rng_need -= gotent;
#else
/* XXX a bad idea; see 7811 block above */
add_true_randomness(num[0]);
@@ -651,11 +670,23 @@
#ifdef __OpenBSD__
timeout_add(&sc->sc_rngto, sc->sc_rnghz);
#else
- callout_reset(&sc->sc_rngto, sc->sc_rnghz, hifn_rng, sc);
+ if (sc->sc_rng_need > 0) {
+ callout_reset(&sc->sc_rngto, sc->sc_rnghz, hifn_rng, sc);
+ }
#endif
}
static void
+hifn_rng(void *vsc)
+{
+ struct hifn_softc *sc = vsc;
+
+ mutex_spin_enter(&sc->sc_mtx);
+ hifn_rng_locked(vsc);
+ mutex_spin_exit(&sc->sc_mtx);
+}
+
+static void
hifn_puc_wait(struct hifn_softc *sc)
{
int i;
@@ -1590,7 +1621,7 @@
{
struct hifn_dma *dma = sc->sc_dma;
u_int32_t cmdlen;
- int cmdi, resi, s, err = 0;
+ int cmdi, resi, err = 0;
if (bus_dmamap_create(sc->sc_dmat, HIFN_MAX_DMALEN, MAX_SCATTER,
HIFN_MAX_SEGLEN, 0, BUS_DMA_NOWAIT, &cmd->src_map))
@@ -1720,21 +1751,17 @@
0, cmd->dst_map->dm_mapsize, BUS_DMASYNC_PREREAD);
}
- s = splnet();
-
/*
* need 1 cmd, and 1 res
* need N src, and N dst
*/
if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE ||
(dma->resu + 1) > HIFN_D_RES_RSIZE) {
- splx(s);
err = ENOMEM;
goto err_dstmap;
}
if ((dma->srcu + cmd->src_map->dm_nsegs) > HIFN_D_SRC_RSIZE ||
(dma->dstu + cmd->dst_map->dm_nsegs + 1) > HIFN_D_DST_RSIZE) {
- splx(s);
err = ENOMEM;
goto err_dstmap;
}
@@ -1837,7 +1864,6 @@
#endif
sc->sc_active = 5;
- splx(s);
return (err); /* success */
err_dstmap:
@@ -1860,9 +1886,8 @@
hifn_tick(void *vsc)
{
struct hifn_softc *sc = vsc;
- int s;
- s = splnet();
+ mutex_spin_enter(&sc->sc_mtx);
if (sc->sc_active == 0) {
struct hifn_dma *dma = sc->sc_dma;
u_int32_t r = 0;
@@ -1891,12 +1916,12 @@
}
else
sc->sc_active--;
- splx(s);
#ifdef __OpenBSD__
timeout_add(&sc->sc_tickto, hz);
#else
callout_reset(&sc->sc_tickto, hz, hifn_tick, sc);
#endif
+ mutex_spin_exit(&sc->sc_mtx);
}
static int
@@ -1917,9 +1942,13 @@
dma->cmdu, dma->srcu, dma->dstu, dma->resu);
#endif
+ mutex_spin_enter(&sc->sc_mtx);
+
/* Nothing in the DMA unit interrupted */
- if ((dmacsr & sc->sc_dmaier) == 0)
+ if ((dmacsr & sc->sc_dmaier) == 0) {
+ mutex_spin_exit(&sc->sc_mtx);
return (0);
+ }
WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier);
@@ -1948,7 +1977,7 @@
printf("%s: abort, resetting.\n", device_xname(sc->sc_dv));
hifnstats.hst_abort++;
hifn_abort(sc);
- return (1);
+ goto out;
}
if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->resu == 0)) {
@@ -2026,6 +2055,8 @@
}
dma->cmdk = i; dma->cmdu = u;
+out:
+ mutex_spin_exit(&sc->sc_mtx);
return (1);
}
@@ -2039,17 +2070,21 @@
{
struct cryptoini *c;
struct hifn_softc *sc = arg;
- int i, mac = 0, cry = 0, comp = 0;
+ int i, mac = 0, cry = 0, comp = 0, retval = EINVAL;
KASSERT(sc != NULL /*, ("hifn_newsession: null softc")*/);
if (sidp == NULL || cri == NULL || sc == NULL)
- return (EINVAL);
+ return retval;
+ mutex_spin_enter(&sc->sc_mtx);
+
for (i = 0; i < sc->sc_maxses; i++)
if (sc->sc_sessions[i].hs_state == HS_STATE_FREE)
break;
- if (i == sc->sc_maxses)
- return (ENOMEM);
+ if (i == sc->sc_maxses) {
+ retval = ENOMEM;
+ goto out;
+ }
for (c = cri; c != NULL; c = c->cri_next) {
switch (c->cri_alg) {
@@ -2057,8 +2092,9 @@
case CRYPTO_SHA1:
case CRYPTO_MD5_HMAC_96:
case CRYPTO_SHA1_HMAC_96:
- if (mac)
- return (EINVAL);
+ if (mac) {
+ goto out;
+ }
mac = 1;
break;
case CRYPTO_DES_CBC:
@@ -2082,35 +2118,42 @@
#endif
/*FALLTHROUGH*/
case CRYPTO_ARC4:
- if (cry)
- return (EINVAL);
+ if (cry) {
+ goto out;
+ }
cry = 1;
break;
#ifdef HAVE_CRYPTO_LZS
case CRYPTO_LZS_COMP:
- if (comp)
- return (EINVAL);
+ if (comp) {
+ goto out;
+ }
comp = 1;
break;
#endif
default:
- return (EINVAL);
+ goto out;
}
}
- if (mac == 0 && cry == 0 && comp == 0)
- return (EINVAL);
+ if (mac == 0 && cry == 0 && comp == 0) {
+ goto out;
+ }
/*
* XXX only want to support compression without chaining to
* MAC/crypt engine right now
*/
- if ((comp && mac) || (comp && cry))
- return (EINVAL);
+ if ((comp && mac) || (comp && cry)) {
+ goto out;
+ }
*sidp = HIFN_SID(device_unit(sc->sc_dv), i);
sc->sc_sessions[i].hs_state = HS_STATE_USED;
- return (0);
+ retval = 0;
+out:
+ mutex_spin_exit(&sc->sc_mtx);
+ return retval;
}
/*
@@ -2129,11 +2172,15 @@
if (sc == NULL)
return (EINVAL);
+ mutex_spin_enter(&sc->sc_mtx);
session = HIFN_SESSION(sid);
- if (session >= sc->sc_maxses)
+ if (session >= sc->sc_maxses) {
+ mutex_spin_exit(&sc->sc_mtx);
return (EINVAL);
+ }
memset(&sc->sc_sessions[session], 0, sizeof(sc->sc_sessions[session]));
+ mutex_spin_exit(&sc->sc_mtx);
return (0);
}
@@ -2149,6 +2196,8 @@
hifnstats.hst_invalid++;
return (EINVAL);
}
+
+ mutex_spin_enter(&sc->sc_mtx);
session = HIFN_SESSION(crp->crp_sid);
if (sc == NULL || session >= sc->sc_maxses) {
@@ -2377,6 +2426,7 @@
enccrd->crd_flags & CRD_F_ENCRYPT;
if (sc->sc_sessions[session].hs_state == HS_STATE_USED)
sc->sc_sessions[session].hs_state = HS_STATE_KEY;
+ mutex_spin_exit(&sc->sc_mtx);
return 0;
} else if (err == ERESTART) {
/*
@@ -2390,6 +2440,7 @@
#endif
free(cmd, M_DEVBUF);
sc->sc_needwakeup |= CRYPTO_SYMQ;
+ mutex_spin_exit(&sc->sc_mtx);
return (err);
}
@@ -2401,6 +2452,7 @@
else
hifnstats.hst_nomem++;
crp->crp_etype = err;
+ mutex_spin_exit(&sc->sc_mtx);
crypto_done(crp);
return (0);
}
@@ -2716,9 +2768,7 @@
cmd->session_num = 0;
cmd->softc = sc;
- s = splnet();
err = hifn_compress_enter(sc, cmd);
- splx(s);
if (err != 0)
goto fail;
@@ -2745,9 +2795,6 @@
return (0);
}
-/*
- * must be called at splnet()
- */
static int
hifn_compress_enter(struct hifn_softc *sc, struct hifn_command *cmd)
{
@@ -2921,7 +2968,6 @@
bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
0, cmd->dst_map->dm_mapsize, BUS_DMASYNC_PREREAD);
- /* already at splnet... */
err = hifn_compress_enter(sc, cmd);
if (err != 0)
goto out;
--- src/sys/dev/pci/ubsec.c 2012/10/27 17:18:35 1.28
+++ src/sys/dev/pci/ubsec.c 2013/06/13 00:55:01 1.29
@@ -1,4 +1,4 @@
-/* $NetBSD: ubsec.c,v 1.28 2012/10/27 17:18:35 chs Exp $ */
+/* $NetBSD: ubsec.c,v 1.29 2013/06/13 00:55:01 tls Exp $ */
/* $FreeBSD: src/sys/dev/ubsec/ubsec.c,v 1.6.2.6 2003/01/23 21:06:43 sam Exp $ */
/* $OpenBSD: ubsec.c,v 1.127 2003/06/04 14:04:58 jason Exp $ */
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ubsec.c,v 1.28 2012/10/27 17:18:35 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ubsec.c,v 1.29 2013/06/13 00:55:01 tls Exp $");
#undef UBSEC_DEBUG
@@ -48,9 +48,9 @@
#include <sys/proc.h>
#include <sys/endian.h>
#ifdef __NetBSD__
+ #define UBSEC_NO_RNG /* hangs on attach */
#define letoh16 htole16
#define letoh32 htole32
-#define UBSEC_NO_RNG /* until statistically tested */
#endif
#include <sys/errno.h>
#include <sys/malloc.h>
@@ -119,7 +119,9 @@
static void ubsec_callback2(struct ubsec_softc *, struct ubsec_q2 *);
static void ubsec_feed2(struct ubsec_softc *);
#ifndef UBSEC_NO_RNG
-static void ubsec_rng(void *);
+static void ubsec_rng(void *);
+static void ubsec_rng_locked(void *);
+static void ubsec_rng_get(size_t, void *);
#endif /* UBSEC_NO_RNG */
static int ubsec_dma_malloc(struct ubsec_softc *, bus_size_t,
struct ubsec_dma_alloc *, int);
@@ -359,6 +361,9 @@
return;
}
+ sc->sc_rng_need = RND_POOLBITS / NBBY;
+ mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
+
SIMPLEQ_INIT(&sc->sc_freequeue);
dmap = sc->sc_dmaa;
for (i = 0; i < UBS_MAX_NQUEUE; i++, dmap++) {
@@ -430,6 +435,10 @@
goto skip_rng;
}
+ rndsource_setcb(&sc->sc_rnd_source, ubsec_rng_get, sc);
+ rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dev),
+ RND_TYPE_RNG,
+ RND_FLAG_NO_ESTIMATE|RND_FLAG_HASCB);
if (hz >= 100)
sc->sc_rnghz = hz / 100;
else
@@ -474,9 +483,11 @@
struct ubsec_dma *dmap;
int npkts = 0, i;
+ mutex_spin_enter(&sc->sc_mtx);
stat = READ_REG(sc, BS_STAT);
stat &= sc->sc_statmask;
if (stat == 0) {
+ mutex_spin_exit(&sc->sc_mtx);
return (0);
}
@@ -583,6 +594,7 @@
sc->sc_needwakeup &= ~wkeup;
crypto_unblock(sc->sc_cid, wkeup);
}
+ mutex_spin_exit(&sc->sc_mtx);
return (1);
}
@@ -926,7 +938,7 @@
#ifdef __OpenBSD__
int card;
#endif
- int err = 0, i, j, s, nicealign;
+ int err = 0, i, j, nicealign;
struct ubsec_softc *sc;
struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
int encoffset = 0, macoffset = 0, cpskip, cpoffset;
@@ -948,18 +960,18 @@
return (EINVAL);
}
- s = splnet();
+ mutex_spin_enter(&sc->sc_mtx);
if (SIMPLEQ_EMPTY(&sc->sc_freequeue)) {
ubsecstats.hst_queuefull++;
sc->sc_needwakeup |= CRYPTO_SYMQ;
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
return(ERESTART);
}
q = SIMPLEQ_FIRST(&sc->sc_freequeue);
SIMPLEQ_REMOVE_HEAD(&sc->sc_freequeue, /*q,*/ q_next);
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
dmap = q->q_dma; /* Save dma pointer */
memset(q, 0, sizeof(struct ubsec_q));
@@ -1436,14 +1448,14 @@
offsetof(struct ubsec_dmachunk, d_ctx), &ctx,
sizeof(struct ubsec_pktctx));
- s = splnet();
+ mutex_spin_enter(&sc->sc_mtx);
SIMPLEQ_INSERT_TAIL(&sc->sc_queue, q, q_next);
sc->sc_nqueue++;
ubsecstats.hst_ipackets++;
ubsecstats.hst_ibytes += dmap->d_alloc.dma_map->dm_mapsize;
if ((hint & CRYPTO_HINT_MORE) == 0 || sc->sc_nqueue >= ubsec_maxbatch)
ubsec_feed(sc);
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
return (0);
errout:
@@ -1460,9 +1472,9 @@
bus_dmamap_destroy(sc->sc_dmat, q->q_src_map);
}
- s = splnet();
+ mutex_spin_enter(&sc->sc_mtx);
SIMPLEQ_INSERT_TAIL(&sc->sc_freequeue, q, q_next);
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
}
#if 0 /* jonathan says: this openbsd code seems to be subsumed elsewhere */
if (err == EINVAL)
@@ -1638,13 +1650,18 @@
add_true_randomness(letoh32(*p));
rng->rng_used = 0;
#else
- /* XXX NetBSD rnd subsystem too weak */
- i = 0; (void)i; /* shut off gcc warnings */
+ i = UBSEC_RNG_BUFSIZ * sizeof(u_int32_t);
+ rnd_add_data(&sc->sc_rnd_source, (char *)p, i, i * NBBY);
+ sc->sc_rng_need -= i;
+ rng->rng_used = 0;
#endif
#ifdef __OpenBSD__
timeout_add(&sc->sc_rngto, sc->sc_rnghz);
#else
- callout_reset(&sc->sc_rngto, sc->sc_rnghz, ubsec_rng, sc);
+ if (sc->sc_rng_need > 0) {
+ callout_reset(&sc->sc_rngto, sc->sc_rnghz,
+ ubsec_rng, sc);
+ }
#endif
break;
}
@@ -1727,20 +1744,48 @@
}
#ifndef UBSEC_NO_RNG
+
static void
+ubsec_rng_get(size_t bytes, void *vsc)
+{
+ struct ubsec_softc *sc = vsc;
+
+ mutex_spin_enter(&sc->sc_mtx);
+ sc->sc_rng_need = bytes;
+ ubsec_rng_locked(sc);
+ mutex_spin_exit(&sc->sc_mtx);
+
+}
+
+static void
ubsec_rng(void *vsc)
{
struct ubsec_softc *sc = vsc;
+ mutex_spin_enter(&sc->sc_mtx);
+ ubsec_rng_locked(sc);
+ mutex_spin_exit(&sc->sc_mtx);
+}
+
+static void
+ubsec_rng_locked(void *vsc)
+{
+ struct ubsec_softc *sc = vsc;
struct ubsec_q2_rng *rng = &sc->sc_rng;
struct ubsec_mcr *mcr;
struct ubsec_ctx_rngbypass *ctx;
- int s;
- s = splnet();
+ mutex_spin_enter(&sc->sc_mtx);
if (rng->rng_used) {
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
return;
}
+
+ if (sc->sc_rng_need < 1) {
+ callout_stop(&sc->sc_rngto);
+ mutex_spin_exit(&sc->sc_mtx);
+ return;
+ }
+
sc->sc_nqueue2++;
if (sc->sc_nqueue2 >= UBS_MAX_NQUEUE)
goto out;
@@ -1770,7 +1815,7 @@
rng->rng_used = 1;
ubsec_feed2(sc);
ubsecstats.hst_rng++;
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
return;
@@ -1779,7 +1824,7 @@
* Something weird happened, generate our own call back.
*/
sc->sc_nqueue2--;
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
#ifdef __OpenBSD__
timeout_add(&sc->sc_rngto, sc->sc_rnghz);
#else
@@ -2097,7 +2142,7 @@
struct ubsec_mcr *mcr;
struct ubsec_ctx_modexp *ctx;
struct ubsec_pktbuf *epb;
- int s, err = 0;
+ int err = 0;
u_int nbits, normbits, mbits, shiftbits, ebits;
me = (struct ubsec_q2_modexp *)malloc(sizeof *me, M_DEVBUF, M_NOWAIT);
@@ -2254,11 +2299,11 @@
0, me->me_epb.dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
/* Enqueue and we're done... */
- s = splnet();
+ mutex_spin_enter(&sc->sc_mtx);
SIMPLEQ_INSERT_TAIL(&sc->sc_queue2, &me->me_q, q_next);
ubsec_feed2(sc);
ubsecstats.hst_modexp++;
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
return (0);
@@ -2302,7 +2347,7 @@
struct ubsec_mcr *mcr;
struct ubsec_ctx_modexp *ctx;
struct ubsec_pktbuf *epb;
- int s, err = 0;
+ int err = 0;
u_int nbits, normbits, mbits, shiftbits, ebits;
me = (struct ubsec_q2_modexp *)malloc(sizeof *me, M_DEVBUF, M_NOWAIT);
@@ -2459,10 +2504,10 @@
0, me->me_epb.dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
/* Enqueue and we're done... */
- s = splnet();
+ mutex_spin_enter(&sc->sc_mtx);
SIMPLEQ_INSERT_TAIL(&sc->sc_queue2, &me->me_q, q_next);
ubsec_feed2(sc);
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
return (0);
@@ -2502,7 +2547,7 @@
struct ubsec_q2_rsapriv *rp = NULL;
struct ubsec_mcr *mcr;
struct ubsec_ctx_rsapriv *ctx;
- int s, err = 0;
+ int err = 0;
u_int padlen, msglen;
msglen = ubsec_ksigbits(&krp->krp_param[UBS_RSAPRIV_PAR_P]);
@@ -2655,11 +2700,11 @@
0, rp->rpr_msgout.dma_map->dm_mapsize, BUS_DMASYNC_PREREAD);
/* Enqueue and we're done... */
- s = splnet();
+ mutex_spin_enter(&sc->sc_mtx);
SIMPLEQ_INSERT_TAIL(&sc->sc_queue2, &rp->rpr_q, q_next);
ubsec_feed2(sc);
ubsecstats.hst_modexpcrt++;
- splx(s);
+ mutex_spin_exit(&sc->sc_mtx);
return (0);
errout:
--- src/sys/dev/pci/ubsecvar.h 2012/10/27 17:18:35 1.4
+++ src/sys/dev/pci/ubsecvar.h 2013/06/13 00:55:01 1.5
@@ -1,4 +1,4 @@
-/* $NetBSD: ubsecvar.h,v 1.4 2012/10/27 17:18:35 chs Exp $ */
+/* $NetBSD: ubsecvar.h,v 1.5 2013/06/13 00:55:01 tls Exp $ */
/* $OpenBSD: ubsecvar.h,v 1.36 2003/06/04 16:02:41 jason Exp $ */
/*
@@ -149,6 +149,7 @@
struct ubsec_softc {
device_t sc_dev; /* generic device */
void *sc_ih; /* interrupt handler cookie */
+ kmutex_t sc_mtx;
bus_space_handle_t sc_sh; /* memory handle */
bus_space_tag_t sc_st; /* memory tag */
bus_dma_tag_t sc_dmat; /* dma tag */
@@ -170,6 +171,8 @@
struct callout sc_rngto; /* rng timeout */
int sc_rnghz; /* rng poll time */
struct ubsec_q2_rng sc_rng;
+ krndsource_t sc_rnd_source;
+ int sc_rng_need; /* how many bytes wanted */
struct ubsec_dma sc_dmaa[UBS_MAX_NQUEUE];
struct ubsec_q *sc_queuea[UBS_MAX_NQUEUE];
SIMPLEQ_HEAD(,ubsec_q2) sc_q2free; /* free list */
--- src/sys/dev/scsipi/sd.c 2013/05/29 00:47:49 1.300
+++ src/sys/dev/scsipi/sd.c 2013/06/13 00:55:01 1.301
@@ -1,4 +1,4 @@
-/* $NetBSD: sd.c,v 1.300 2013/05/29 00:47:49 christos Exp $ */
+/* $NetBSD: sd.c,v 1.301 2013/06/13 00:55:01 tls Exp $ */
/*-
* Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc.
@@ -47,7 +47,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.300 2013/05/29 00:47:49 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.301 2013/06/13 00:55:01 tls Exp $");
#include "opt_scsi.h"
@@ -215,7 +215,7 @@
struct sd_softc *sd = device_private(self);
struct scsipibus_attach_args *sa = aux;
struct scsipi_periph *periph = sa->sa_periph;
- int error, result, rndval = cprng_strong32();
+ int error, result;
struct disk_parms *dp = &sd->params;
char pbuf[9];
@@ -328,16 +328,16 @@
* these bits, on insertion, because the deltas to the
* nonexistent) previous event should never allow it.
*/
- rnd_add_uint32(&sd->rnd_source, rndval);
+ rnd_add_uint32(&sd->rnd_source, 0);
}
static int
sddetach(device_t self, int flags)
{
struct sd_softc *sd = device_private(self);
- int s, bmaj, cmaj, i, mn, rc, rndval = cprng_strong32();
+ int s, bmaj, cmaj, i, mn, rc;
- rnd_add_uint32(&sd->rnd_source, rndval);
+ rnd_add_uint32(&sd->rnd_source, 0);
if ((rc = disk_begindetach(&sd->sc_dk, sdlastclose, self, flags)) != 0)
return rc;
--- src/sys/kern/Attic/kern_rndpool.c 2012/04/17 02:50:38 1.2
+++ src/sys/kern/Attic/kern_rndpool.c 2013/06/13 00:55:01 1.3
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_rndpool.c,v 1.2 2012/04/17 02:50:38 tls Exp $ */
+/* $NetBSD: kern_rndpool.c,v 1.3 2013/06/13 00:55:01 tls Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_rndpool.c,v 1.2 2012/04/17 02:50:38 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_rndpool.c,v 1.3 2013/06/13 00:55:01 tls Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -51,9 +51,12 @@
/*
* Let others know: the pool is full.
+ *
+ * XXX these should be per-pool if we really mean to allow multiple pools.
*/
int rnd_full = 0; /* Flag: is the pool full? */
int rnd_filled = 0; /* Count: how many times filled? */
+int rnd_empty = 1; /* Flag: is the pool empty? */
static inline void rndpool_add_one_word(rndpool_t *, u_int32_t);
--- src/sys/kern/Attic/kern_rndq.c 2013/01/26 22:22:07 1.10
+++ src/sys/kern/Attic/kern_rndq.c 2013/06/13 00:55:01 1.11
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_rndq.c,v 1.10 2013/01/26 22:22:07 tls Exp $ */
+/* $NetBSD: kern_rndq.c,v 1.11 2013/06/13 00:55:01 tls Exp $ */
/*-
* Copyright (c) 1997-2013 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.10 2013/01/26 22:22:07 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.11 2013/06/13 00:55:01 tls Exp $");
#include <sys/param.h>
#include <sys/ioctl.h>
@@ -46,6 +46,7 @@
#include <sys/conf.h>
#include <sys/systm.h>
#include <sys/callout.h>
+#include <sys/intr.h>
#include <sys/rnd.h>
#include <sys/vnode.h>
#include <sys/pool.h>
@@ -99,10 +100,13 @@
* The event queue. Fields are altered at an interrupt level.
* All accesses must be protected with the mutex.
*/
-volatile int rnd_timeout_pending;
SIMPLEQ_HEAD(, _rnd_sample_t) rnd_samples;
kmutex_t rnd_mtx;
+/*
+ * This lock protects dispatch of our soft interrupts.
+ */
+kmutex_t rndsoft_mtx;
/*
* Entropy sinks: usually other generators waiting to be rekeyed.
@@ -149,14 +153,15 @@
.test_cnt = 0,
.test = NULL
};
+void *rnd_process, *rnd_wakeup;
+struct callout skew_callout;
-struct callout rnd_callout, skew_callout;
-
void rnd_wakeup_readers(void);
static inline u_int32_t rnd_estimate_entropy(krndsource_t *, u_int32_t);
static inline u_int32_t rnd_counter(void);
-static void rnd_timeout(void *);
-static void rnd_process_events(void *);
+static void rnd_intr(void *);
+static void rnd_wake(void *);
+static void rnd_process_events(void);
u_int32_t rnd_extract_data_locked(void *, u_int32_t, u_int32_t); /* XXX */
static void rnd_add_data_ts(krndsource_t *, const void *const,
uint32_t, uint32_t, uint32_t);
@@ -196,22 +201,101 @@
}
/*
+ * We may be called from low IPL -- protect our softint.
+ */
+
+static inline void
+rnd_schedule_softint(void *softint)
+{
+ mutex_spin_enter(&rndsoft_mtx);
+ softint_schedule(softint);
+ mutex_spin_exit(&rndsoft_mtx);
+}
+
+/*
+ * XXX repulsive: we can't initialize our softints in rnd_init
+ * XXX (too early) so we wrap the points where we'd schedule them, thus.
+ */
+static inline void
+rnd_schedule_process(void)
+{
+ if (__predict_true(rnd_process)) {
+ rnd_schedule_softint(rnd_process);
+ return;
+ }
+ if (!cold) {
+ rnd_process = softint_establish(SOFTINT_SERIAL|SOFTINT_MPSAFE,
+ rnd_intr, NULL);
+ }
+ rnd_process_events();
+}
+
+static inline void
+rnd_schedule_wakeup(void)
+{
+ if (__predict_true(rnd_wakeup)) {
+ rnd_schedule_softint(rnd_wakeup);
+ return;
+ }
+ if (!cold) {
+ rnd_wakeup = softint_establish(SOFTINT_CLOCK|SOFTINT_MPSAFE,
+ rnd_wake, NULL);
+ }
+ rnd_wakeup_readers();
+}
+
+/*
+ * Tell any sources with "feed me" callbacks that we are hungry.
+ */
+static void
+rnd_getmore(size_t byteswanted)
+{
+ krndsource_t *rs;
+
+ KASSERT(mutex_owned(&rndpool_mtx));
+
+ LIST_FOREACH(rs, &rnd_sources, list) {
+ if (rs->flags & RND_FLAG_HASCB) {
+ KASSERT(rs->get != NULL);
+ KASSERT(rs->getarg != NULL);
+ rs->get((size_t)byteswanted, rs->getarg);
+#ifdef RND_VERBOSE
+ printf("rnd: asking source %s for %d bytes\n",
+ rs->name, (int)byteswanted);
+#endif
+ }
+ }
+}
+
+/*
* Check to see if there are readers waiting on us. If so, kick them.
*/
void
rnd_wakeup_readers(void)
{
rndsink_t *sink, *tsink;
+ size_t entropy_count;
TAILQ_HEAD(, rndsink) sunk = TAILQ_HEAD_INITIALIZER(sunk);
mutex_spin_enter(&rndpool_mtx);
- if (rndpool_get_entropy_count(&rnd_pool) < RND_ENTROPY_THRESHOLD * 8) {
+ entropy_count = rndpool_get_entropy_count(&rnd_pool);
+ if (entropy_count < RND_ENTROPY_THRESHOLD * 8) {
+ rnd_empty = 1;
mutex_spin_exit(&rndpool_mtx);
return;
+ } else {
+#ifdef RND_VERBOSE
+ if (__predict_false(!rnd_initial_entropy)) {
+ printf("rnd: have initial entropy (%u)\n",
+ (unsigned int)entropy_count);
+ }
+#endif
+ rnd_empty = 0;
+ rnd_initial_entropy = 1;
}
/*
- * First, take care of in-kernel consumers needing rekeying.
+ * First, take care of consumers needing rekeying.
*/
mutex_spin_enter(&rndsink_mtx);
TAILQ_FOREACH_SAFE(sink, &rnd_sinks, tailq, tsink) {
@@ -225,8 +309,7 @@
KASSERT(RSTATE_PENDING == sink->state);
- if ((sink->len + RND_ENTROPY_THRESHOLD) * 8 <
- rndpool_get_entropy_count(&rnd_pool)) {
+ if (sink->len * 8 < rndpool_get_entropy_count(&rnd_pool)) {
/* We have enough entropy to sink some here. */
if (rndpool_extract_data(&rnd_pool, sink->data,
sink->len, RND_EXTRACT_GOOD)
@@ -239,28 +322,20 @@
TAILQ_REMOVE(&rnd_sinks, sink, tailq);
TAILQ_INSERT_HEAD(&sunk, sink, tailq);
} else {
- mutex_exit(&sink->mtx);
- }
- }
- mutex_spin_exit(&rndsink_mtx);
-
- /*
- * If we still have enough new bits to do something, feed userspace.
- */
- if (rndpool_get_entropy_count(&rnd_pool) > RND_ENTROPY_THRESHOLD * 8) {
#ifdef RND_VERBOSE
- if (!rnd_initial_entropy)
- printf("rnd: have initial entropy (%u)\n",
- rndpool_get_entropy_count(&rnd_pool));
+ printf("sink wants %d, we have %d, asking for more\n",
+ (int)sink->len * 8,
+ (int)rndpool_get_entropy_count(&rnd_pool));
#endif
- rnd_initial_entropy = 1;
- mutex_spin_exit(&rndpool_mtx);
- } else {
- mutex_spin_exit(&rndpool_mtx);
+ mutex_spin_exit(&sink->mtx);
+ rnd_getmore(sink->len * 8);
+ }
}
+ mutex_spin_exit(&rndsink_mtx);
+ mutex_spin_exit(&rndpool_mtx);
/*
- * Now that we have dropped the mutex, we can run sinks' callbacks.
+ * Now that we have dropped the mutexes, we can run sinks' callbacks.
* Since we have reused the "tailq" member of the sink structure for
* this temporary on-stack queue, the callback must NEVER re-add
* the sink to the main queue, or our on-stack queue will become
@@ -378,10 +453,8 @@
mutex_init(&rnd_mtx, MUTEX_DEFAULT, IPL_VM);
mutex_init(&rndsink_mtx, MUTEX_DEFAULT, IPL_VM);
+ mutex_init(&rndsoft_mtx, MUTEX_DEFAULT, IPL_VM);
- callout_init(&rnd_callout, CALLOUT_MPSAFE);
- callout_setfunc(&rnd_callout, rnd_timeout, NULL);
-
/*
* take a counter early, hoping that there's some variance in
* the following operations
@@ -757,26 +830,10 @@
SIMPLEQ_REMOVE_HEAD(&tmp_samples, next);
SIMPLEQ_INSERT_HEAD(&rnd_samples, state, next);
}
-
- /*
- * If we are still starting up, cause immediate processing of
- * the queued samples. Otherwise, if the timeout isn't
- * pending, have it run in the near future.
- */
- if (__predict_false(cold)) {
-#ifdef RND_VERBOSE
- printf("rnd: directly processing boot-time events.\n");
-#endif
- rnd_process_events(NULL); /* Drops lock! */
- return;
- }
- if (rnd_timeout_pending == 0) {
- rnd_timeout_pending = 1;
- mutex_spin_exit(&rnd_mtx);
- callout_schedule(&rnd_callout, 1);
- return;
- }
mutex_spin_exit(&rnd_mtx);
+
+ /* Cause processing of queued samples */
+ rnd_schedule_process();
}
static int
@@ -837,14 +894,16 @@
* by the add routines directly if the callout has never fired (that
* is, if we are "cold" -- just booted).
*
- * Call with rnd_mtx held -- WILL RELEASE IT.
*/
static void
-rnd_process_events(void *arg)
+rnd_process_events(void)
{
- rnd_sample_t *sample;
+ rnd_sample_t *sample = NULL;
krndsource_t *source, *badsource = NULL;
+ static krndsource_t *last_source;
u_int32_t entropy;
+ size_t pool_entropy;
+ int found = 0, wake = 0;
SIMPLEQ_HEAD(, _rnd_sample_t) dq_samples =
SIMPLEQ_HEAD_INITIALIZER(dq_samples);
SIMPLEQ_HEAD(, _rnd_sample_t) df_samples =
@@ -856,7 +915,9 @@
* and drop lock.
*/
+ mutex_spin_enter(&rnd_mtx);
while ((sample = SIMPLEQ_FIRST(&rnd_samples))) {
+ found++;
SIMPLEQ_REMOVE_HEAD(&rnd_samples, next);
/*
* We repeat this check here, since it is possible
@@ -874,12 +935,36 @@
/* Don't thrash the rndpool mtx either. Hold, add all samples. */
mutex_spin_enter(&rndpool_mtx);
+
+ pool_entropy = rndpool_get_entropy_count(&rnd_pool);
+ if (pool_entropy > RND_ENTROPY_THRESHOLD * 8) {
+ wake++;
+ } else {
+ rnd_empty = 1;
+ rnd_getmore((RND_POOLBITS - pool_entropy) / 8);
+#ifdef RND_VERBOSE
+ printf("rnd: empty, asking for %d bits\n",
+ (int)((RND_POOLBITS - pool_entropy) / 8));
+#endif
+ }
+
while ((sample = SIMPLEQ_FIRST(&dq_samples))) {
SIMPLEQ_REMOVE_HEAD(&dq_samples, next);
source = sample->source;
entropy = sample->entropy;
/*
+ * Don't provide a side channel for timing attacks on
+ * low-rate sources: require mixing with some other
+ * source before we schedule a wakeup.
+ */
+ if (!wake &&
+ (source != last_source || source->flags & RND_FLAG_FAST)) {
+ wake++;
+ }
+ last_source = source;
+
+ /*
* Hardware generators are great but sometimes they
* have...hardware issues. Don't use any data from
* them unless it passes some tests.
@@ -925,27 +1010,32 @@
rnd_sample_free(sample);
}
+
/*
* Wake up any potential readers waiting.
*/
- rnd_wakeup_readers();
+ if (wake) {
+ rnd_schedule_wakeup();
+ }
}
-/*
- * Timeout, run to process the events in the ring buffer.
- */
static void
-rnd_timeout(void *arg)
+rnd_intr(void *arg)
{
- mutex_spin_enter(&rnd_mtx);
- rnd_timeout_pending = 0;
- rnd_process_events(arg);
+ rnd_process_events();
}
+static void
+rnd_wake(void *arg)
+{
+ rnd_wakeup_readers();
+}
+
u_int32_t
rnd_extract_data_locked(void *p, u_int32_t len, u_int32_t flags)
{
static int timed_in;
+ int entropy_count;
KASSERT(mutex_owned(&rndpool_mtx));
if (__predict_false(!timed_in)) {
@@ -969,8 +1059,6 @@
#ifdef DIAGNOSTIC
while (!rnd_tested) {
- int entropy_count;
-
entropy_count = rndpool_get_entropy_count(&rnd_pool);
#ifdef RND_VERBOSE
printf("rnd: starting statistical RNG test, entropy = %d.\n",
@@ -1012,6 +1100,10 @@
rnd_tested++;
}
#endif
+ entropy_count = rndpool_get_entropy_count(&rnd_pool);
+ if (entropy_count < (RND_ENTROPY_THRESHOLD * 2 + len) * 8) {
+ rnd_getmore(RND_POOLBITS - entropy_count * 8);
+ }
return rndpool_extract_data(&rnd_pool, p, len, flags);
}
@@ -1041,13 +1133,7 @@
TAILQ_INSERT_TAIL(&rnd_sinks, rs, tailq);
mutex_spin_exit(&rndsink_mtx);
- mutex_spin_enter(&rnd_mtx);
- if (rnd_timeout_pending == 0) {
- rnd_timeout_pending = 1;
- callout_schedule(&rnd_callout, 1);
- }
- mutex_spin_exit(&rnd_mtx);
-
+ rnd_schedule_process();
}
void
--- src/sys/kern/subr_cprng.c 2013/03/28 18:06:48 1.16
+++ src/sys/kern/subr_cprng.c 2013/06/13 00:55:01 1.17
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_cprng.c,v 1.16 2013/03/28 18:06:48 tls Exp $ */
+/* $NetBSD: subr_cprng.c,v 1.17 2013/06/13 00:55:01 tls Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -46,7 +46,7 @@
#include <sys/cprng.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.16 2013/03/28 18:06:48 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.17 2013/06/13 00:55:01 tls Exp $");
void
cprng_init(void)
@@ -200,8 +200,17 @@
if (r != sizeof(key)) {
if (c->flags & CPRNG_INIT_ANY) {
#ifdef DEBUG
- printf("cprng %s: WARNING insufficient "
- "entropy at creation.\n", name);
+ /*
+ * If we have ever crossed the pool's
+ * minimum-entropy threshold, then we are
+ * providing cryptographically strong
+ * random output -- if not information-
+ * theoretically strong. Warn elsewise.
+ */
+ if (!rnd_initial_entropy) {
+ printf("cprng %s: WARNING insufficient "
+ "entropy at creation.\n", name);
+ }
#endif
} else {
hard++;
--- src/sys/sys/rnd.h 2013/01/26 19:05:11 1.35
+++ src/sys/sys/rnd.h 2013/06/13 00:55:01 1.36
@@ -1,4 +1,4 @@
-/* $NetBSD: rnd.h,v 1.35 2013/01/26 19:05:11 tls Exp $ */
+/* $NetBSD: rnd.h,v 1.36 2013/06/13 00:55:01 tls Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -92,6 +92,7 @@
#define RND_FLAG_NO_ESTIMATE 0x00000100 /* don't estimate entropy */
#define RND_FLAG_NO_COLLECT 0x00000200 /* don't collect entropy */
#define RND_FLAG_FAST 0x00000400 /* process samples in bulk */
+#define RND_FLAG_HASCB 0x00000800 /* has get callback */
#define RND_TYPE_UNKNOWN 0 /* unknown source */
#define RND_TYPE_DISK 1 /* source is physical disk */
@@ -127,8 +128,17 @@
void *state; /* state information */
size_t test_cnt; /* how much test data accumulated? */
rngtest_t *test; /* test data for RNG type sources */
+ void (*get)(size_t, void *); /* pool wants N bytes (badly) */
+ void *getarg; /* argument to get-function */
} krndsource_t;
+static inline void
+rndsource_setcb(struct krndsource *const rs, void *const cb, void *const arg)
+{
+ rs->get = cb;
+ rs->getarg = arg;
+}
+
enum rsink_st {
RSTATE_IDLE = 0,
RSTATE_PENDING,
@@ -186,6 +196,7 @@
}
}
+extern int rnd_empty;
extern int rnd_full;
extern int rnd_filled;
extern int rnd_initial_entropy;