Module Name:    src
Committed By:   tls
Date:           Sat Feb 27 00:43:55 UTC 2016

Modified Files:
        src/sys/arch/x86/x86: cpu_rng.c

Log Message:
Add RDSEED and RDRAND backends for cpu_rng on amd64 and i386.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/x86/x86/cpu_rng.c

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/x86/x86/cpu_rng.c
diff -u src/sys/arch/x86/x86/cpu_rng.c:1.1 src/sys/arch/x86/x86/cpu_rng.c:1.2
--- src/sys/arch/x86/x86/cpu_rng.c:1.1	Sat Feb 27 00:09:45 2016
+++ src/sys/arch/x86/x86/cpu_rng.c	Sat Feb 27 00:43:55 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu_rng.c,v 1.1 2016/02/27 00:09:45 tls Exp $ */
+/* $NetBSD: cpu_rng.c,v 1.2 2016/02/27 00:43:55 tls Exp $ */
 
 /*-
  * Copyright (c) 2015 The NetBSD Foundation, Inc.
@@ -42,24 +42,95 @@
 static enum {
 	CPU_RNG_NONE = 0,
 	CPU_RNG_RDRAND,
-	CPU_RNG_RDSEED,
-	CPU_RNG_VIA } cpu_rng_mode __read_mostly = CPU_RNG_NONE;
+	CPU_RNG_RDSEED } cpu_rng_mode __read_mostly = CPU_RNG_NONE;
 
 bool
 cpu_rng_init(void)
 {
+
+	if (cpu_feature[5] & CPUID_SEF_RDSEED) {
+		cpu_rng_mode = CPU_RNG_RDSEED;
+		aprint_normal("cpu_rng: RDSEED\n");
+		return true;
+	} else if (cpu_feature[1] & CPUID2_RDRAND) {
+		cpu_rng_mode = CPU_RNG_RDRAND;
+		aprint_normal("cpu_rng: RDRAND\n");
+		return true;
+	}
 	return false;
 }
 
+static inline size_t
+cpu_rng_rdrand(cpu_rng_t *out)
+{
+	uint8_t rndsts;
+
+#ifdef __i386__
+	uint32_t lo, hi;
+
+	__asm __volatile("rdrand %0; setc %1" : "=r"(lo), "=qm"(rndsts));
+	if (rndsts != 1)
+		return 0;
+	__asm __volatile("rdrand %0; setc %1" : "=r"(hi), "=qm"(rndsts));
+
+	*out = (uint64_t)lo | ((uint64_t)hi << 32);
+	explicit_memset(&lo, 0, sizeof(lo));
+	explicit_memset(&hi, 0, sizeof(hi));
+	if (rndsts != 1)
+		return sizeof(lo) * NBBY;
+#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;
+
+#ifdef __i386__
+	uint32_t lo, hi;
+	
+	__asm __volatile("rdseed %0; setc %1" : "=r"(lo), "=qm"(rndsts));
+        if (rndsts != 1)
+		goto exhausted;
+	__asm __volatile("rdseed %0; setc %1" : "=r"(hi), "=qm"(rndsts));
+	if (rndsts != 1)
+		goto exhausted;
+
+	*out = (uint64_t)lo | ((uint64_t)hi << 32);
+	explicit_memset(&lo, 0, sizeof(lo));
+	explicit_memset(&hi, 0, sizeof(hi));
+#else
+	__asm __volatile("rdseed %0; setc %1" : "=r"(*out), "=qm"(rndsts));
+#endif
+	if (rndsts != 1)
+		goto exhausted;
+
+	return sizeof(*out) * NBBY;
+
+	/*
+	 * Userspace could have exhausted RDSEED, but the
+	 * CPU-internal generator feeding RDRAND is guaranteed
+	 * to be seeded even in this case.
+	 */
+exhausted:
+	return cpu_rng_rdrand(out);
+}
+
 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:
-	case CPU_RNG_VIA:
-		return 0;
+		return cpu_rng_rdrand(out);
 	default:
 		panic("cpu_rng: unknown mode %d", (int)cpu_rng_mode);
 	}

Reply via email to