tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
x86 CPU RNG support, take 2
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 tech%openbsd.org@localhost 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.
Home |
Main Index |
Thread Index |
Old Index