summaryrefslogtreecommitdiff
path: root/random
diff options
context:
space:
mode:
authorDmitry Kasatkin <dmitry.kasatkin@intel.com>2012-12-18 14:56:48 +0200
committerWerner Koch <wk@gnupg.org>2012-12-18 19:33:04 +0100
commitefd7002188e6d50013e4d9a920a8b9afa9d210e5 (patch)
tree09adb14c6f19c50a45ae5c2fb3067c08435506d5 /random
parentbfe4dc11bb822cbc5bf2b425e5a5a2867a904518 (diff)
downloadlibgcrypt-efd7002188e6d50013e4d9a920a8b9afa9d210e5.tar.gz
Add support for using DRNG random number generator
* configure.ac: Add option --disable-drng-support. (ENABLE_DRNG_SUPPORT): New. * random/rndhw.c (USE_DRNG): New. (rdrand_long, rdrand_nlong, poll_drng): New. (_gcry_rndhw_poll_fast, _gcry_rndhw_poll_slow): Call poll function. * src/g10lib.h (HWF_INTEL_RDRAND): New. * src/global.c (hwflist): Add "intel-rdrand". * src/hwfeatures.c (detect_x86_64_gnuc) [ENABLE_DRNG_SUPPORT]: Detect RDRAND. (detect_ia32_gnuc) [ENABLE_DRNG_SUPPORT]: Detect RDRAND. -- This patch provides support for using Digital Random Number Generator (DRNG) engine, which is available on the latest Intel's CPUs. DRNG engine is accesible via new the RDRAND instruction. This patch adds the following: - support for disabling using of rdrand instruction - checking for RDRAND instruction support using cpuid - RDRAND usage implementation Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com> ChangeLog and editorial changes by wk.
Diffstat (limited to 'random')
-rw-r--r--random/rndhw.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/random/rndhw.c b/random/rndhw.c
index 775d90f0..cbb28d1a 100644
--- a/random/rndhw.c
+++ b/random/rndhw.c
@@ -1,5 +1,6 @@
/* rndhw.c - Access to the external random daemon
* Copyright (C) 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2012 Dmitry Kasatkin
*
* This file is part of Libgcrypt.
*
@@ -34,6 +35,16 @@
# endif
#endif /*ENABLE_PADLOCK_SUPPORT*/
+#undef USE_DRNG
+#ifdef ENABLE_DRNG_SUPPORT
+# ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
+# if (defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__)
+# define USE_DRNG 1
+# endif
+# endif
+#endif /*ENABLE_RDRAND_SUPPORT*/
+
+typedef void (*add_fn_t)(const void*, size_t, enum random_origins);
/* Keep track on whether the RNG has problems. */
static volatile int rng_failed;
@@ -109,6 +120,55 @@ poll_padlock (void (*add)(const void*, size_t, enum random_origins),
#endif /*USE_PADLOCK*/
+#ifdef USE_DRNG
+# define RDRAND_RETRY_LOOPS 10
+# define RDRAND_INT ".byte 0x0f,0xc7,0xf0"
+# ifdef __x86_64__
+# define RDRAND_LONG ".byte 0x48,0x0f,0xc7,0xf0"
+# else
+# define RDRAND_LONG RDRAND_INT
+# endif
+static inline int
+rdrand_long (unsigned long *v)
+{
+ int ok;
+ asm volatile ("1: " RDRAND_LONG "\n\t"
+ "jc 2f\n\t"
+ "decl %0\n\t"
+ "jnz 1b\n\t"
+ "2:"
+ : "=r" (ok), "=a" (*v)
+ : "0" (RDRAND_RETRY_LOOPS));
+ return ok;
+}
+
+
+static inline int
+rdrand_nlong (unsigned long *v, int count)
+{
+ while (count--)
+ if (!rdrand_long(v++))
+ return 0;
+ return 1;
+}
+
+
+static size_t
+poll_drng (add_fn_t add, enum random_origins origin, int fast)
+{
+ volatile char buffer[64] __attribute__ ((aligned (8)));
+ unsigned int nbytes = sizeof (buffer);
+
+ (void)fast;
+
+ if (!rdrand_nlong ((unsigned long *)buffer, sizeof(buffer)/sizeof(long)))
+ return 0;
+ (*add)((void *)buffer, nbytes, origin);
+ return nbytes;
+}
+#endif /*USE_DRNG*/
+
+
int
_gcry_rndhw_failed_p (void)
{
@@ -125,6 +185,10 @@ _gcry_rndhw_poll_fast (void (*add)(const void*, size_t, enum random_origins),
(void)add;
(void)origin;
+#ifdef USE_DRNG
+ if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND))
+ poll_drng (add, origin, 1);
+#endif
#ifdef USE_PADLOCK
if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG))
poll_padlock (add, origin, 1);
@@ -143,6 +207,10 @@ _gcry_rndhw_poll_slow (void (*add)(const void*, size_t, enum random_origins),
(void)add;
(void)origin;
+#ifdef USE_DRNG
+ if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND))
+ nbytes += poll_drng (add, origin, 0);
+#endif
#ifdef USE_PADLOCK
if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG))
nbytes += poll_padlock (add, origin, 0);