Module Name: src Committed By: tls Date: Thu Jun 13 00:55:01 UTC 2013
Modified Files: src/sys/arch/arm/broadcom: bcm2835_rng.c src/sys/dev: rndpseudo.c src/sys/dev/pci: amdpm.c amdpm_smbus.c amdpmvar.h hifn7751.c hifn7751var.h ubsec.c ubsecvar.h src/sys/dev/scsipi: sd.c src/sys/kern: kern_rndpool.c kern_rndq.c subr_cprng.c src/sys/sys: rnd.h Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/broadcom/bcm2835_rng.c cvs rdiff -u -r1.11 -r1.12 src/sys/dev/rndpseudo.c cvs rdiff -u -r1.36 -r1.37 src/sys/dev/pci/amdpm.c cvs rdiff -u -r1.19 -r1.20 src/sys/dev/pci/amdpm_smbus.c cvs rdiff -u -r1.9 -r1.10 src/sys/dev/pci/amdpmvar.h \ src/sys/dev/pci/hifn7751var.h cvs rdiff -u -r1.51 -r1.52 src/sys/dev/pci/hifn7751.c cvs rdiff -u -r1.28 -r1.29 src/sys/dev/pci/ubsec.c cvs rdiff -u -r1.4 -r1.5 src/sys/dev/pci/ubsecvar.h cvs rdiff -u -r1.300 -r1.301 src/sys/dev/scsipi/sd.c cvs rdiff -u -r1.2 -r1.3 src/sys/kern/kern_rndpool.c cvs rdiff -u -r1.10 -r1.11 src/sys/kern/kern_rndq.c cvs rdiff -u -r1.16 -r1.17 src/sys/kern/subr_cprng.c cvs rdiff -u -r1.35 -r1.36 src/sys/sys/rnd.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/broadcom/bcm2835_rng.c diff -u src/sys/arch/arm/broadcom/bcm2835_rng.c:1.3 src/sys/arch/arm/broadcom/bcm2835_rng.c:1.4 --- src/sys/arch/arm/broadcom/bcm2835_rng.c:1.3 Fri Feb 1 16:10:16 2013 +++ src/sys/arch/arm/broadcom/bcm2835_rng.c Thu Jun 13 00:55:01 2013 @@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: bcm2835_rng. #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 @@ struct bcm2835rng_softc { 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,11 +104,11 @@ bcmrng_attach(device_t parent, device_t return; } - rnd_attach_source(&sc->sc_rnd, device_xname(self), RND_TYPE_RNG, - RND_FLAG_NO_ESTIMATE); + mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); - callout_init(&sc->sc_tick, CALLOUT_MPSAFE); - callout_setfunc(&sc->sc_tick, bcmrng_tick, sc); + 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_HASCB); /* 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 @@ bcmrng_attach(device_t parent, device_t 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); } Index: src/sys/dev/rndpseudo.c diff -u src/sys/dev/rndpseudo.c:1.11 src/sys/dev/rndpseudo.c:1.12 --- src/sys/dev/rndpseudo.c:1.11 Sun Nov 25 15:29:24 2012 +++ src/sys/dev/rndpseudo.c Thu Jun 13 00:55:01 2013 @@ -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 @@ rndopen(dev_t dev, int flag, int ifmt, } 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 @@ rnd_read(struct file * fp, off_t *offp, /* 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 @@ rnd_read(struct file * fp, off_t *offp, (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) { Index: src/sys/dev/pci/amdpm.c diff -u src/sys/dev/pci/amdpm.c:1.36 src/sys/dev/pci/amdpm.c:1.37 --- src/sys/dev/pci/amdpm.c:1.36 Sat Oct 27 17:18:28 2012 +++ src/sys/dev/pci/amdpm.c Thu Jun 13 00:55:01 2013 @@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: amdpm.c,v 1. #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 @@ __KERNEL_RCSID(0, "$NetBSD: amdpm.c,v 1. #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 @@ amdpm_match(device_t parent, cfdata_t ma } 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_attach(device_t parent, device_t s 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 @@ amdpm_attach(device_t parent, device_t s 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 @@ amdpm_attach(device_t parent, device_t s * 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 @@ amdpm_attach(device_t parent, device_t s "rnd data"); } #endif + sc->sc_rnd_need = RND_POOLBITS / NBBY; amdpm_rnd_callout(sc); } } @@ -208,7 +227,7 @@ CFATTACH_DECL_NEW(amdpm, sizeof(struct a 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 @@ amdpm_rnd_callout(void *v) 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 @@ amdpm_rnd_callout(void *v) 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); } Index: src/sys/dev/pci/amdpm_smbus.c diff -u src/sys/dev/pci/amdpm_smbus.c:1.19 src/sys/dev/pci/amdpm_smbus.c:1.20 --- src/sys/dev/pci/amdpm_smbus.c:1.19 Sat Oct 27 17:18:28 2012 +++ src/sys/dev/pci/amdpm_smbus.c Thu Jun 13 00:55:01 2013 @@ -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_pub...@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> @@ -83,8 +83,6 @@ amdpm_smbus_attach(struct amdpm_softc *s 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); } Index: src/sys/dev/pci/amdpmvar.h diff -u src/sys/dev/pci/amdpmvar.h:1.9 src/sys/dev/pci/amdpmvar.h:1.10 --- src/sys/dev/pci/amdpmvar.h:1.9 Sat Oct 27 17:18:28 2012 +++ src/sys/dev/pci/amdpmvar.h Thu Jun 13 00:55:01 2013 @@ -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 amdpm_softc { 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; Index: src/sys/dev/pci/hifn7751var.h diff -u src/sys/dev/pci/hifn7751var.h:1.9 src/sys/dev/pci/hifn7751var.h:1.10 --- src/sys/dev/pci/hifn7751var.h:1.9 Sat Oct 27 17:18:32 2012 +++ src/sys/dev/pci/hifn7751var.h Thu Jun 13 00:55:01 2013 @@ -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 hifn_softc { 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 @@ struct hifn_softc { 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)) Index: src/sys/dev/pci/hifn7751.c diff -u src/sys/dev/pci/hifn7751.c:1.51 src/sys/dev/pci/hifn7751.c:1.52 --- src/sys/dev/pci/hifn7751.c:1.51 Sat Oct 27 17:18:32 2012 +++ src/sys/dev/pci/hifn7751.c Thu Jun 13 00:55:01 2013 @@ -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 @@ static int hifn_dmamap_load_dst(struct h 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 @@ static void hifn_callback_comp(struct hi u_int8_t *); #endif /* HAVE_CRYPTO_LZS */ - struct hifn_stats hifnstats; static const struct hifn_product { @@ -418,14 +419,18 @@ hifn_attach(device_t parent, device_t se 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 @@ fail_io0: 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 @@ hifn_init_pubrng(struct hifn_softc *sc) 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 @@ hifn_init_pubrng(struct hifn_softc *sc) * 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 @@ hifn_init_pubrng(struct hifn_softc *sc) #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 @@ hifn_init_pubrng(struct hifn_softc *sc) } static void -hifn_rng(void *vsc) +hifn_rng_locked(void *vsc) { struct hifn_softc *sc = vsc; #ifdef __NetBSD__ @@ -551,6 +569,12 @@ hifn_rng(void *vsc) #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? */ @@ -569,14 +593,12 @@ hifn_rng(void *vsc) */ 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 @@ hifn_rng(void *vsc) } } 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 @@ hifn_rng(void *vsc) * 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 @@ hifn_rng(void *vsc) #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 @@ hifn_crypto(struct hifn_softc *sc, struc { 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 @@ hifn_crypto(struct hifn_softc *sc, struc 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 @@ hifn_crypto(struct hifn_softc *sc, struc #endif sc->sc_active = 5; - splx(s); return (err); /* success */ err_dstmap: @@ -1860,9 +1886,8 @@ static void 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 @@ hifn_tick(void *vsc) } 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 @@ hifn_intr(void *arg) 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 @@ hifn_intr(void *arg) 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 @@ hifn_intr(void *arg) } dma->cmdk = i; dma->cmdu = u; +out: + mutex_spin_exit(&sc->sc_mtx); return (1); } @@ -2039,17 +2070,21 @@ hifn_newsession(void *arg, u_int32_t *si { 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 @@ hifn_newsession(void *arg, u_int32_t *si 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 @@ hifn_newsession(void *arg, u_int32_t *si #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 @@ hifn_freesession(void *arg, u_int64_t ti 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 @@ hifn_process(void *arg, struct cryptop * 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 @@ hifn_process(void *arg, struct cryptop * 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 @@ hifn_process(void *arg, struct cryptop * #endif free(cmd, M_DEVBUF); sc->sc_needwakeup |= CRYPTO_SYMQ; + mutex_spin_exit(&sc->sc_mtx); return (err); } @@ -2401,6 +2452,7 @@ errout: else hifnstats.hst_nomem++; crp->crp_etype = err; + mutex_spin_exit(&sc->sc_mtx); crypto_done(crp); return (0); } @@ -2716,9 +2768,7 @@ hifn_compression(struct hifn_softc *sc, 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 @@ fail: return (0); } -/* - * must be called at splnet() - */ static int hifn_compress_enter(struct hifn_softc *sc, struct hifn_command *cmd) { @@ -2921,7 +2968,6 @@ hifn_callback_comp(struct hifn_softc *sc 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; Index: src/sys/dev/pci/ubsec.c diff -u src/sys/dev/pci/ubsec.c:1.28 src/sys/dev/pci/ubsec.c:1.29 --- src/sys/dev/pci/ubsec.c:1.28 Sat Oct 27 17:18:35 2012 +++ src/sys/dev/pci/ubsec.c Thu Jun 13 00:55:01 2013 @@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: ubsec.c,v 1. #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_mcopy(struct mbuf *, s 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 @@ ubsec_attach(device_t parent, device_t s 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 @@ ubsec_attach(device_t parent, device_t s 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 @@ ubsec_intr(void *arg) 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 @@ ubsec_intr(void *arg) sc->sc_needwakeup &= ~wkeup; crypto_unblock(sc->sc_cid, wkeup); } + mutex_spin_exit(&sc->sc_mtx); return (1); } @@ -926,7 +938,7 @@ ubsec_process(void *arg, struct cryptop #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 @@ ubsec_process(void *arg, struct cryptop 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 @@ ubsec_process(void *arg, struct cryptop 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 @@ errout: 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 @@ ubsec_callback2(struct ubsec_softc *sc, 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 @@ ubsec_callback2(struct ubsec_softc *sc, } #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 @@ ubsec_rng(void *vsc) rng->rng_used = 1; ubsec_feed2(sc); ubsecstats.hst_rng++; - splx(s); + mutex_spin_exit(&sc->sc_mtx); return; @@ -1779,7 +1824,7 @@ out: * 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 @@ ubsec_kprocess_modexp_sw(struct ubsec_so 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 @@ ubsec_kprocess_modexp_sw(struct ubsec_so 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 @@ ubsec_kprocess_modexp_hw(struct ubsec_so 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 @@ ubsec_kprocess_modexp_hw(struct ubsec_so 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 @@ ubsec_kprocess_rsapriv(struct ubsec_soft 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 @@ ubsec_kprocess_rsapriv(struct ubsec_soft 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: Index: src/sys/dev/pci/ubsecvar.h diff -u src/sys/dev/pci/ubsecvar.h:1.4 src/sys/dev/pci/ubsecvar.h:1.5 --- src/sys/dev/pci/ubsecvar.h:1.4 Sat Oct 27 17:18:35 2012 +++ src/sys/dev/pci/ubsecvar.h Thu Jun 13 00:55:01 2013 @@ -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_q { 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 ubsec_softc { 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 */ Index: src/sys/dev/scsipi/sd.c diff -u src/sys/dev/scsipi/sd.c:1.300 src/sys/dev/scsipi/sd.c:1.301 --- src/sys/dev/scsipi/sd.c:1.300 Wed May 29 00:47:49 2013 +++ src/sys/dev/scsipi/sd.c Thu Jun 13 00:55:01 2013 @@ -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 @@ sdattach(device_t parent, device_t self, 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 @@ sdattach(device_t parent, device_t self, * 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; Index: src/sys/kern/kern_rndpool.c diff -u src/sys/kern/kern_rndpool.c:1.2 src/sys/kern/kern_rndpool.c:1.3 --- src/sys/kern/kern_rndpool.c:1.2 Tue Apr 17 02:50:38 2012 +++ src/sys/kern/kern_rndpool.c Thu Jun 13 00:55:01 2013 @@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: kern_rndpool /* * 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); Index: src/sys/kern/kern_rndq.c diff -u src/sys/kern/kern_rndq.c:1.10 src/sys/kern/kern_rndq.c:1.11 --- src/sys/kern/kern_rndq.c:1.10 Sat Jan 26 22:22:07 2013 +++ src/sys/kern/kern_rndq.c Thu Jun 13 00:55:01 2013 @@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: kern_rndq.c, #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 @@ typedef struct _rnd_sample_t { * 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 @@ static krndsource_t rnd_source_no_collec .test_cnt = 0, .test = NULL }; - -struct callout rnd_callout, skew_callout; +void *rnd_process, *rnd_wakeup; +struct 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 @@ rnd_counter(void) } /* + * 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 @@ rnd_wakeup_readers(void) 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 @@ rnd_wakeup_readers(void) 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,9 +453,7 @@ rnd_init(void) mutex_init(&rnd_mtx, MUTEX_DEFAULT, IPL_VM); mutex_init(&rndsink_mtx, MUTEX_DEFAULT, IPL_VM); - - callout_init(&rnd_callout, CALLOUT_MPSAFE); - callout_setfunc(&rnd_callout, rnd_timeout, NULL); + mutex_init(&rndsoft_mtx, MUTEX_DEFAULT, IPL_VM); /* * take a counter early, hoping that there's some variance in @@ -757,26 +830,10 @@ rnd_add_data_ts(krndsource_t *rs, const 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 @@ rnd_hwrng_test(rnd_sample_t *sample) * 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 @@ rnd_process_events(void *arg) * 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 @@ rnd_process_events(void *arg) /* 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_process_events(void *arg) 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 @@ rnd_extract_data_locked(void *p, u_int32 #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_extract_data_locked(void *p, u_int32 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 @@ rndsink_attach(rndsink_t *rs) 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 Index: src/sys/kern/subr_cprng.c diff -u src/sys/kern/subr_cprng.c:1.16 src/sys/kern/subr_cprng.c:1.17 --- src/sys/kern/subr_cprng.c:1.16 Thu Mar 28 18:06:48 2013 +++ src/sys/kern/subr_cprng.c Thu Jun 13 00:55:01 2013 @@ -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 @@ cprng_strong_create(const char *const na 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++; Index: src/sys/sys/rnd.h diff -u src/sys/sys/rnd.h:1.35 src/sys/sys/rnd.h:1.36 --- src/sys/sys/rnd.h:1.35 Sat Jan 26 19:05:11 2013 +++ src/sys/sys/rnd.h Thu Jun 13 00:55:01 2013 @@ -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 @@ typedef struct { #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 @@ typedef struct krndsource { 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 @@ rnd_add_uint32(krndsource_t *kr, uint32_ } } +extern int rnd_empty; extern int rnd_full; extern int rnd_filled; extern int rnd_initial_entropy;