I've cleaned it up a little and hooked it up as a standard entropy source per Taylor's comments. To avoid a pile of largely pointless config glue, it is an internal source in kern_rndq.c just like the "callout" source. I think this can probably be used for the onboard RNG on other CPUs as well.
I've also modified the VIA backend -- we now enable the dual noise sources on newer CPUs, and grab a single RNG buffer without copying. These ideas came from http://tech.openbsd.narkive.com/F5TDMblw/via-c7-dual-rng . I've asked for testers for that part of the patch on port-i386 and port-amd64. I would appreciate comments from anyone who has time to read the code. Thor
Index: arch/amd64/include/Makefile =================================================================== RCS file: /Volumes/NB/repo/src/sys/arch/amd64/include/Makefile,v retrieving revision 1.18 diff -u -p -r1.18 Makefile --- arch/amd64/include/Makefile 23 Jul 2014 18:19:43 -0000 1.18 +++ arch/amd64/include/Makefile 19 Dec 2015 22:17:36 -0000 @@ -4,7 +4,7 @@ INCSDIR= /usr/include/amd64 INCS= ansi.h aout_machdep.h asm.h \ bootinfo.h bswap.h byte_swap.h \ - cdefs.h cpu.h \ + cdefs.h cpu.h cpu_rng.h\ disklabel.h \ elf_machdep.h endian.h endian_machdep.h \ float.h fpu.h frame.h frame_regs.h \ Index: arch/amd64/include/types.h =================================================================== RCS file: /Volumes/NB/repo/src/sys/arch/amd64/include/types.h,v retrieving revision 1.48 diff -u -p -r1.48 types.h --- arch/amd64/include/types.h 27 Aug 2015 12:30:50 -0000 1.48 +++ arch/amd64/include/types.h 19 Dec 2015 21:39:37 -0000 @@ -93,6 +93,7 @@ typedef unsigned char __cpu_simple_lock #define __HAVE_TLS_VARIANT_II #define __HAVE_COMMON___TLS_GET_ADDR #define __HAVE_INTR_CONTROL +#define __HAVE_CPU_RNG #ifdef _KERNEL_OPT #define __HAVE_RAS Index: arch/i386/include/Makefile =================================================================== RCS file: /Volumes/NB/repo/src/sys/arch/i386/include/Makefile,v retrieving revision 1.43 diff -u -p -r1.43 Makefile --- arch/i386/include/Makefile 23 Jul 2014 18:19:44 -0000 1.43 +++ arch/i386/include/Makefile 19 Dec 2015 22:16:58 -0000 @@ -4,7 +4,7 @@ INCSDIR= /usr/include/i386 INCS= ansi.h aout_machdep.h apmvar.h asm.h \ bioscall.h bootinfo.h bswap.h byte_swap.h \ - cdefs.h cpu.h cputypes.h \ + cdefs.h cpu.h cpu_rng.h cputypes.h \ disklabel.h \ elf_machdep.h endian.h endian_machdep.h \ fenv.h float.h frame.h freebsd_machdep.h \ Index: arch/i386/include/types.h =================================================================== RCS file: /Volumes/NB/repo/src/sys/arch/i386/include/types.h,v retrieving revision 1.83 diff -u -p -r1.83 types.h --- arch/i386/include/types.h 27 Aug 2015 12:30:51 -0000 1.83 +++ arch/i386/include/types.h 19 Dec 2015 21:40:33 -0000 @@ -109,6 +109,8 @@ typedef unsigned char __cpu_simple_lock #define __HAVE_SYSCALL_INTERN #define __HAVE_MINIMAL_EMUL #define __HAVE_OLD_DISKLABEL +#define __HAVE_CPU_RNG + #if defined(_KERNEL) /* * Processors < i586 do not have cmpxchg8b, and we compile for i486 Index: arch/x86/conf/files.x86 =================================================================== RCS file: /Volumes/NB/repo/src/sys/arch/x86/conf/files.x86,v retrieving revision 1.85 diff -u -p -r1.85 files.x86 --- arch/x86/conf/files.x86 11 Nov 2015 08:20:22 -0000 1.85 +++ arch/x86/conf/files.x86 25 Dec 2015 22:32:35 -0000 @@ -27,6 +27,7 @@ define ipmibus {} device cpu: cpufeaturebus attach cpu at cpubus file arch/x86/x86/cpu.c cpu +file arch/x86/x86/cpu_rng.c cpu device acpicpu: acpi attach acpicpu at cpufeaturebus Index: arch/x86/include/Makefile =================================================================== RCS file: /Volumes/NB/repo/src/sys/arch/x86/include/Makefile,v retrieving revision 1.19 diff -u -p -r1.19 Makefile --- arch/x86/include/Makefile 11 Feb 2014 20:17:16 -0000 1.19 +++ arch/x86/include/Makefile 19 Dec 2015 21:46:23 -0000 @@ -7,6 +7,7 @@ INCS= aout_machdep.h \ cacheinfo.h \ cpu.h \ cpu_extended_state.h \ + cpu_rng.h \ cpu_ucode.h \ cputypes.h \ cpuvar.h \ Index: arch/x86/include/cpu_rng.h =================================================================== RCS file: arch/x86/include/cpu_rng.h diff -N arch/x86/include/cpu_rng.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/x86/include/cpu_rng.h 25 Dec 2015 22:57:30 -0000 @@ -0,0 +1,49 @@ +/* $NetBSD: $ */ + +#ifndef _X86_CPURNG_H_ +#define _X86_CPURNG_H_ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Thor Lancelot Simon. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/cpu.h> + +#include <x86/specialreg.h> + +#include <machine/cpufunc.h> +#include <machine/cpuvar.h> + +typedef uint64_t cpu_rng_t; + +void cpu_rng_init(void); +size_t cpu_rng(cpu_rng_t *); + +#endif Index: arch/x86/include/via_padlock.h =================================================================== RCS file: /Volumes/NB/repo/src/sys/arch/x86/include/via_padlock.h,v retrieving revision 1.8 diff -u -p -r1.8 via_padlock.h --- arch/x86/include/via_padlock.h 13 Apr 2015 16:03:51 -0000 1.8 +++ arch/x86/include/via_padlock.h 25 Dec 2015 22:10:56 -0000 @@ -59,11 +59,6 @@ struct via_padlock_softc { uint8_t op_iv[16]; /* 128 bit aligned */ void *op_buf; - int sc_rnd_hz; - struct callout sc_rnd_co; - krndsource_t sc_rnd_source; - bool sc_rnd_attached; - /* normal softc stuff */ int32_t sc_cid; bool sc_cid_attached; @@ -74,8 +69,6 @@ struct via_padlock_softc { #define VIAC3_SESSION(sid) ((sid) & 0x0fffffff) #define VIAC3_SID(crd,ses) (((crd) << 28) | ((ses) & 0x0fffffff)) -#define VIAC3_RNG_BUFSIZ 16 - #endif /* _KERNEL */ #if defined(_KERNEL) || defined(_KMEMUSER) Index: arch/x86/x86/cpu_rng.c =================================================================== RCS file: arch/x86/x86/cpu_rng.c diff -N arch/x86/x86/cpu_rng.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/x86/x86/cpu_rng.c 25 Dec 2015 22:58:39 -0000 @@ -0,0 +1,166 @@ +/* $NetBSD: $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Thor Lancelot Simon. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * The VIA RNG code in this file is inspired by Jason Wright and + * Theo de Raadt's OpenBSD version but has been rewritten in light of + * comments from Henric Jungheim on the t...@openbsd.org mailing list. + */ + +#include <machine/cpu_rng.h> + +static enum { CPU_RNG_NONE = 0, + CPU_RNG_RDRAND, + CPU_RNG_RDSEED, + CPU_RNG_VIA } cpu_rng_mode = CPU_RNG_NONE; + +void +cpu_rng_init(void) +{ + if (cpu_feature[5] & CPUID_SEF_RDSEED) { + cpu_rng_mode = CPU_RNG_RDSEED; + aprint_normal("cpu_rng: RDSEED\n"); + } else + + if (cpu_feature[1] & CPUID2_RDRAND) { + cpu_rng_mode = CPU_RNG_RDRAND; + aprint_normal("cpu_rng: RDRAND\n"); + } else + + if (cpu_feature[4] & CPUID_VIA_HAS_RNG) { + cpu_rng_mode = CPU_RNG_VIA; + aprint_normal("cpu_rng: VIA\n"); + } +} + +static inline size_t +cpu_rng_rdrand(cpu_rng_t *out) +{ + uint8_t rndsts; +#ifndef __x86_64__ + uint32_t outword[2] = out; + int i; + + for (i = 0; i < 2; i++) { + __asm __volatile("rdrand %0; setc %1":"=r"(outword + i), + "=qm"(rndsts)); + if (rndsts != 1) return 0; + } +#else + __asm __volatile("rdrand %0; setc %1":"=r"(out), + "=qm"(rndsts)); + if (rndsts != 1) return 0; +#endif + return sizeof(*out) * NBBY; +} + +static inline size_t +cpu_rng_rdseed(cpu_rng_t *out) +{ + uint8_t rndsts; + +#ifndef __x86_64__ + uint32_t outword[2] = out; + int i; + + for (i = 0; i < 2; i++) { + __asm __volatile("rdseed %0; setc %1":"=r"(outword + i), + "=qm"(rndsts)); + + /* + * Userspace could have exhausted RDSEED, but the + * CPU-internal generator feeding RDRAND is guaranteed + * to be seeded even in this case. + */ + if (rndsts != 1) return cpu_rng_rdrand(out); + } +#else + __asm __volatile("rdseed %0; setc %1":"=r"(out), + "=qm"(rndsts)); + if (rndsts != 1) return cpu_rng_rdrand(out); +#endif + return sizeof(*out) * NBBY; +} + +static size_t +cpu_rng_via(cpu_rng_t *out) +{ + uint32_t creg0, rndsts; + + /* + * Sadly, we have to monkey with the coprocessor enable and fault + * registers, which are really for the FPU, in order to read + * from the RNG. + * + * Don't remove CR0_TS from the call below -- comments in the Linux + * driver indicate that the xstorerng instruction can generate + * spurious DNA faults though no FPU or SIMD state is changed + * even if such a fault is generated. + * + */ + kpreempt_disable(); + x86_disable_intr(); + creg0 = rcr0(); + lcr0(creg0 & ~(CR0_EM|CR0_TS)); /* Permit access to SIMD/FPU path */ + /* + * Read one 8-byte buffer from the VIA RNG. + */ + __asm __volatile("xstorerng" + : "=a" (rndsts), "+D" (out) : "d" (0) : "memory"); + /* Put CR0 back how it was */ + lcr0(creg0); + x86_enable_intr(); + kpreempt_enable(); + + /* + * The Cryptography Research paper on the VIA RNG estimates + * 0.75 bits of entropy per output bit and advises users to + * be "even more conservative". + */ + return rndsts & 0xf ? 0 : sizeof(cpu_rng_t) * NBBY / 2; +} + +size_t +cpu_rng(cpu_rng_t *out) +{ + switch (cpu_rng_mode) { + case CPU_RNG_NONE: + return 0; + case CPU_RNG_RDSEED: + return cpu_rng_rdseed(out); + case CPU_RNG_RDRAND: + return cpu_rng_rdrand(out); + case CPU_RNG_VIA: + return cpu_rng_via(out); + default: + panic("cpu_rng: unknown mode %d", (int)cpu_rng_mode); + } +} Index: arch/x86/x86/identcpu.c =================================================================== RCS file: /Volumes/NB/repo/src/sys/arch/x86/x86/identcpu.c,v retrieving revision 1.49 diff -u -p -r1.49 identcpu.c --- arch/x86/x86/identcpu.c 13 Dec 2015 15:02:19 -0000 1.49 +++ arch/x86/x86/identcpu.c 25 Dec 2015 22:35:37 -0000 @@ -554,8 +554,15 @@ cpu_probe_c3(struct cpu_info *ci) /* Actually do the enables. */ if (rng_enable) { msr = rdmsr(MSR_VIA_RNG); - wrmsr(MSR_VIA_RNG, msr | MSR_VIA_RNG_ENABLE); + /* C7 stepping 8 and subsequent CPUs have dual RNG */ + if (model > 0xA || (model == 0xA && stepping > 0x7)) { + wrmsr(MSR_VIA_RNG, msr | MSR_VIA_RNG_ENABLE | + MSR_VIA_RNG_2NOISE); + } else { + wrmsr(MSR_VIA_RNG, msr | MSR_VIA_RNG_ENABLE); + } } + if (ace_enable) { msr = rdmsr(MSR_VIA_ACE); wrmsr(MSR_VIA_ACE, msr | MSR_VIA_ACE_ENABLE); Index: arch/x86/x86/via_padlock.c =================================================================== RCS file: /Volumes/NB/repo/src/sys/arch/x86/x86/via_padlock.c,v retrieving revision 1.24 diff -u -p -r1.24 via_padlock.c --- arch/x86/x86/via_padlock.c 13 Apr 2015 16:03:51 -0000 1.24 +++ arch/x86/x86/via_padlock.c 25 Dec 2015 22:09:52 -0000 @@ -28,7 +28,6 @@ __KERNEL_RCSID(0, "$NetBSD: via_padlock. #include <sys/kernel.h> #include <sys/device.h> #include <sys/module.h> -#include <sys/rndsource.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/cpu.h> @@ -72,64 +71,6 @@ static __inline void via_padlock_cbc(voi void *); static void -via_c3_rnd(void *arg) -{ - struct via_padlock_softc *sc = arg; - - uint32_t creg0, len = VIAC3_RNG_BUFSIZ; - uint32_t buffer[VIAC3_RNG_BUFSIZ/4 + 1]; /* CPU goes 3 bytes beyond */ - uint32_t eax, ecx, edi; /* XXX write-only, but necessary it seems */ - - /* - * Sadly, we have to monkey with the coprocessor enable and fault - * registers, which are really for the FPU, in order to read - * from the RNG. - * - * Don't remove CR0_TS from the call below -- comments in the Linux - * driver indicate that the xstorerng instruction can generate - * spurious DNA faults though no FPU or SIMD state is changed - * even if such a fault is generated. - * - */ - kpreempt_disable(); - x86_disable_intr(); - creg0 = rcr0(); - lcr0(creg0 & ~(CR0_EM|CR0_TS)); /* Permit access to SIMD/FPU path */ - /* - * Collect the random data from the C3 RNG into our buffer. - * We turn on maximum whitening (is this actually desirable - * if we will feed the data to SHA1?) (%edx[0,1] = "11"). - */ - __asm __volatile("rep xstorerng" - : "=a" (eax), "=c" (ecx), "=D" (edi) - : "d" (3), "D" (buffer), "c" (len) - : "memory", "cc"); - /* Put CR0 back how it was */ - lcr0(creg0); - x86_enable_intr(); - kpreempt_enable(); - rnd_add_data(&sc->sc_rnd_source, buffer, len, len * NBBY); - callout_reset(&sc->sc_rnd_co, sc->sc_rnd_hz, via_c3_rnd, sc); -} - -static void -via_c3_rnd_init(struct via_padlock_softc *sc) -{ - sc->sc_rnd_attached = true; - - if (hz >= 100) { - sc->sc_rnd_hz = 10 * hz / 100; - } else { - sc->sc_rnd_hz = 10; - } - rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dev), - RND_TYPE_RNG, RND_FLAG_COLLECT_VALUE); - callout_init(&sc->sc_rnd_co, 0); - /* Call once to prime the pool early and set callout. */ - via_c3_rnd(sc); -} - -static void via_c3_ace_init(struct via_padlock_softc *sc) { /* @@ -608,7 +549,6 @@ via_padlock_attach_intr(device_t self) aprint_normal("%s:", device_xname(self)); if (cpu_feature[4] & CPUID_VIA_HAS_RNG) { - via_c3_rnd_init(sc); aprint_normal(" RNG"); } if (cpu_feature[4] & CPUID_VIA_HAS_ACE) { @@ -623,12 +563,6 @@ via_padlock_detach(device_t self, int fl { struct via_padlock_softc *sc = device_private(self); - if (sc->sc_rnd_attached) { - callout_halt(&sc->sc_rnd_co, NULL); - callout_destroy(&sc->sc_rnd_co); - rnd_detach_source(&sc->sc_rnd_source); - sc->sc_rnd_attached = false; - } if (sc->sc_cid_attached) { crypto_unregister(sc->sc_cid, CRYPTO_AES_CBC); crypto_unregister(sc->sc_cid, CRYPTO_MD5_HMAC_96); Index: kern/kern_rndq.c =================================================================== RCS file: /Volumes/NB/repo/src/sys/kern/kern_rndq.c,v retrieving revision 1.73 diff -u -p -r1.73 kern_rndq.c --- kern/kern_rndq.c 29 Aug 2015 10:00:19 -0000 1.73 +++ kern/kern_rndq.c 25 Dec 2015 20:04:08 -0000 @@ -59,6 +59,10 @@ __KERNEL_RCSID(0, "$NetBSD: kern_rndq.c, #include <compat/sys/rnd.h> #endif +#if defined(__HAVE_CPU_RNG) +#include <machine/cpu_rng.h> +#endif + #if defined(__HAVE_CPU_COUNTER) #include <machine/cpu_counter.h> #endif @@ -404,6 +408,31 @@ rnd_dv_estimate(krndsource_t *rs, uint32 return ret; } +#if defined(__HAVE_CPU_RNG) +krndsource_t rnd_cpu_source; + +static void +rnd_cpu_get(size_t bytes, void *priv) +{ + krndsource_t *cpusrcp = priv; + size_t entropy = 0, cnt = RND_POOLBITS / 2 / NBBY / sizeof(cpu_rng_t); + cpu_rng_t buf[cnt]; + + KASSERT(cpusrcp == &rnd_cpu_source); + if (RND_ENABLED(cpusrcp)) { + cpu_rng_t *bufp = buf; + for (bufp = buf; bufp < buf + cnt; bufp++) { + entropy += cpu_rng(bufp); + } + if (__predict_true(entropy)) { + rnd_add_data(cpusrcp, buf, sizeof(buf), entropy); + } + explicit_memset(buf, 0, sizeof(buf)); + } +} + +#endif + #if defined(__HAVE_CPU_COUNTER) static struct { kmutex_t lock; @@ -550,6 +579,27 @@ rnd_init(void) } /* + * Attach CPU RNG if available. + */ +#if defined(__HAVE_CPU_RNG) + { + cpu_rng_t test; + + cpu_rng_init(); + if (cpu_rng(&test)) { + rndsource_setcb(&rnd_cpu_source, rnd_cpu_get, + &rnd_cpu_source); + rnd_attach_source(&rnd_cpu_source, "cpurng", + RND_TYPE_RNG, + RND_FLAG_COLLECT_VALUE| + RND_FLAG_HASCB|RND_FLAG_HASENABLE); + rnd_cpu_get(RND_POOLBITS / NBBY, &rnd_cpu_source); + } + explicit_memset(&test, 0, sizeof(test)); + } +#endif + + /* * If we have a cycle counter, take its error with respect * to the callout mechanism as a source of entropy, ala * TrueRand.