svn commit: r347239 - head/sys/dev/random

Conrad Meyer cem at FreeBSD.org
Wed May 8 00:45:17 UTC 2019


Author: cem
Date: Wed May  8 00:45:16 2019
New Revision: 347239
URL: https://svnweb.freebsd.org/changeset/base/347239

Log:
  random: x86 driver: Prefer RDSEED over RDRAND when available
  
  Per
  https://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed
  , RDRAND is a PRNG seeded from the same source as RDSEED.  The source is
  more suitable as PRNG seed material, so prefer it when the RDSEED intrinsic
  is available (indicated in CPU feature bits).
  
  Reviewed by:	delphij, jhb, imp (earlier version)
  Approved by:	secteam(delphij)
  Security:	yes
  Sponsored by:	Dell EMC Isilon
  Differential Revision:	https://reviews.freebsd.org/D20192

Modified:
  head/sys/dev/random/ivy.c

Modified: head/sys/dev/random/ivy.c
==============================================================================
--- head/sys/dev/random/ivy.c	Wed May  8 00:40:08 2019	(r347238)
+++ head/sys/dev/random/ivy.c	Wed May  8 00:45:16 2019	(r347239)
@@ -44,11 +44,13 @@ __FBSDID("$FreeBSD$");
 
 #include <machine/md_var.h>
 #include <machine/specialreg.h>
+#include <x86/ifunc.h>
 
 #include <dev/random/randomdev.h>
 
 #define	RETRY_COUNT	10
 
+static bool has_rdrand, has_rdseed;
 static u_int random_ivy_read(void *, u_int);
 
 static struct random_source random_ivy = {
@@ -57,10 +59,9 @@ static struct random_source random_ivy = {
 	.rs_read = random_ivy_read
 };
 
-static inline int
-ivy_rng_store(u_long *buf)
+static int
+x86_rdrand_store(u_long *buf)
 {
-#ifdef __GNUCLIKE_ASM
 	u_long rndval;
 	int retry;
 
@@ -75,11 +76,40 @@ ivy_rng_store(u_long *buf)
 	    : "+r" (retry), "=r" (rndval) : : "cc");
 	*buf = rndval;
 	return (retry);
-#else /* __GNUCLIKE_ASM */
-	return (0);
-#endif
 }
 
+static int
+x86_rdseed_store(u_long *buf)
+{
+	u_long rndval;
+	int retry;
+
+	retry = RETRY_COUNT;
+	__asm __volatile(
+	    "1:\n\t"
+	    "rdseed	%1\n\t"	/* read randomness into rndval */
+	    "jc		2f\n\t" /* CF is set on success, exit retry loop */
+	    "dec	%0\n\t" /* otherwise, retry-- */
+	    "jne	1b\n\t" /* and loop if retries are not exhausted */
+	    "2:"
+	    : "+r" (retry), "=r" (rndval) : : "cc");
+	*buf = rndval;
+	return (retry);
+}
+
+DEFINE_IFUNC(static, int, x86_rng_store, (u_long *buf), static)
+{
+	has_rdrand = (cpu_feature2 & CPUID2_RDRAND);
+	has_rdseed = (cpu_stdext_feature & CPUID_STDEXT_RDSEED);
+
+	if (has_rdseed)
+		return (x86_rdseed_store);
+	else if (has_rdrand)
+		return (x86_rdrand_store);
+	else
+		return (NULL);
+}
+
 /* It is required that buf length is a multiple of sizeof(u_long). */
 static u_int
 random_ivy_read(void *buf, u_int c)
@@ -90,7 +120,7 @@ random_ivy_read(void *buf, u_int c)
 	KASSERT(c % sizeof(*b) == 0, ("partial read %d", c));
 	b = buf;
 	for (count = c; count > 0; count -= sizeof(*b)) {
-		if (ivy_rng_store(&rndval) == 0)
+		if (x86_rng_store(&rndval) == 0)
 			break;
 		*b++ = rndval;
 	}
@@ -104,14 +134,14 @@ rdrand_modevent(module_t mod, int type, void *unused)
 
 	switch (type) {
 	case MOD_LOAD:
-		if (cpu_feature2 & CPUID2_RDRAND) {
+		if (has_rdrand || has_rdseed) {
 			random_source_register(&random_ivy);
 			printf("random: fast provider: \"%s\"\n", random_ivy.rs_ident);
 		}
 		break;
 
 	case MOD_UNLOAD:
-		if (cpu_feature2 & CPUID2_RDRAND)
+		if (has_rdrand || has_rdseed)
 			random_source_deregister(&random_ivy);
 		break;
 


More information about the svn-src-head mailing list