Thu Jul 30 17:26:24 2020 UTC ()
Cite Cryptography Research evaluation of VIA RNG and give live URL.

(URL verified to be archived in the Internet Archive for posterity)


(riastradh)
diff -r1.18 -r1.19 src/sys/arch/x86/x86/cpu_rng.c

cvs diff -r1.18 -r1.19 src/sys/arch/x86/x86/cpu_rng.c (switch to unified diff)

--- src/sys/arch/x86/x86/cpu_rng.c 2020/07/25 22:10:34 1.18
+++ src/sys/arch/x86/x86/cpu_rng.c 2020/07/30 17:26:23 1.19
@@ -1,327 +1,332 @@ @@ -1,327 +1,332 @@
1/* $NetBSD: cpu_rng.c,v 1.18 2020/07/25 22:10:34 riastradh Exp $ */ 1/* $NetBSD: cpu_rng.c,v 1.19 2020/07/30 17:26:23 riastradh Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 4 * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Thor Lancelot Simon. 8 * by Thor Lancelot Simon.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32/* 32/*
33 * For reference on VIA XSTORERNG, see the VIA PadLock Programming 33 * For reference on VIA XSTORERNG, see the VIA PadLock Programming
34 * Guide (`VIA PPG'), August 4, 2005. 34 * Guide (`VIA PPG'), August 4, 2005.
35 * http://linux.via.com.tw/support/beginDownload.action?eleid=181&fid=261 35 * http://linux.via.com.tw/support/beginDownload.action?eleid=181&fid=261
36 * 36 *
37 * For reference on Intel RDRAND/RDSEED, see the Intel Digital Random 37 * For reference on Intel RDRAND/RDSEED, see the Intel Digital Random
38 * Number Generator Software Implementation Guide (`Intel DRNG SIG'), 38 * Number Generator Software Implementation Guide (`Intel DRNG SIG'),
39 * Revision 2.1, October 17, 2018. 39 * Revision 2.1, October 17, 2018.
40 * https://software.intel.com/sites/default/files/managed/98/4a/DRNG_Software_Implementation_Guide_2.1.pdf 40 * https://software.intel.com/sites/default/files/managed/98/4a/DRNG_Software_Implementation_Guide_2.1.pdf
41 * 41 *
42 * For reference on AMD RDRAND/RDSEED, which are designed to be 42 * For reference on AMD RDRAND/RDSEED, which are designed to be
43 * compatible with Intel RDRAND/RDSEED, see the somewhat less detailed 43 * compatible with Intel RDRAND/RDSEED, see the somewhat less detailed
44 * AMD Random Number Generator documentation, 2017-06-27. 44 * AMD Random Number Generator documentation, 2017-06-27.
45 * https://www.amd.com/system/files/TechDocs/amd-random-number-generator.pdf 45 * https://www.amd.com/system/files/TechDocs/amd-random-number-generator.pdf
46 */ 46 */
47 47
48#include <sys/param.h> 48#include <sys/param.h>
49#include <sys/systm.h> 49#include <sys/systm.h>
50#include <sys/cpu.h> 50#include <sys/cpu.h>
51#include <sys/rndsource.h> 51#include <sys/rndsource.h>
52#include <sys/sha2.h> 52#include <sys/sha2.h>
53 53
54#include <x86/specialreg.h> 54#include <x86/specialreg.h>
55 55
56#include <machine/cpufunc.h> 56#include <machine/cpufunc.h>
57#include <machine/cpuvar.h> 57#include <machine/cpuvar.h>
58#include <machine/cpu_rng.h> 58#include <machine/cpu_rng.h>
59#include <machine/limits.h> 59#include <machine/limits.h>
60 60
61static enum cpu_rng_mode { 61static enum cpu_rng_mode {
62 CPU_RNG_NONE = 0, 62 CPU_RNG_NONE = 0,
63 CPU_RNG_RDRAND, 63 CPU_RNG_RDRAND,
64 CPU_RNG_RDSEED, 64 CPU_RNG_RDSEED,
65 CPU_RNG_RDSEED_RDRAND, 65 CPU_RNG_RDSEED_RDRAND,
66 CPU_RNG_VIA 66 CPU_RNG_VIA
67} cpu_rng_mode __read_mostly = CPU_RNG_NONE; 67} cpu_rng_mode __read_mostly = CPU_RNG_NONE;
68 68
69static const char *const cpu_rng_name[] = { 69static const char *const cpu_rng_name[] = {
70 [CPU_RNG_RDRAND] = "rdrand", 70 [CPU_RNG_RDRAND] = "rdrand",
71 [CPU_RNG_RDSEED] = "rdseed", 71 [CPU_RNG_RDSEED] = "rdseed",
72 [CPU_RNG_RDSEED_RDRAND] = "rdrand/rdseed", 72 [CPU_RNG_RDSEED_RDRAND] = "rdrand/rdseed",
73 [CPU_RNG_VIA] = "via", 73 [CPU_RNG_VIA] = "via",
74}; 74};
75 75
76static struct krndsource cpu_rng_source __read_mostly; 76static struct krndsource cpu_rng_source __read_mostly;
77 77
78static enum cpu_rng_mode 78static enum cpu_rng_mode
79cpu_rng_detect(void) 79cpu_rng_detect(void)
80{ 80{
81 bool has_rdseed = (cpu_feature[5] & CPUID_SEF_RDSEED); 81 bool has_rdseed = (cpu_feature[5] & CPUID_SEF_RDSEED);
82 bool has_rdrand = (cpu_feature[1] & CPUID2_RDRAND); 82 bool has_rdrand = (cpu_feature[1] & CPUID2_RDRAND);
83 bool has_viarng = (cpu_feature[4] & CPUID_VIA_HAS_RNG); 83 bool has_viarng = (cpu_feature[4] & CPUID_VIA_HAS_RNG);
84 84
85 if (has_rdseed && has_rdrand) 85 if (has_rdseed && has_rdrand)
86 return CPU_RNG_RDSEED_RDRAND; 86 return CPU_RNG_RDSEED_RDRAND;
87 else if (has_rdseed) 87 else if (has_rdseed)
88 return CPU_RNG_RDSEED; 88 return CPU_RNG_RDSEED;
89 else if (has_rdrand) 89 else if (has_rdrand)
90 return CPU_RNG_RDRAND; 90 return CPU_RNG_RDRAND;
91 else if (has_viarng) 91 else if (has_viarng)
92 return CPU_RNG_VIA; 92 return CPU_RNG_VIA;
93 else 93 else
94 return CPU_RNG_NONE; 94 return CPU_RNG_NONE;
95} 95}
96 96
97static size_t 97static size_t
98cpu_rng_rdrand(uint64_t *out) 98cpu_rng_rdrand(uint64_t *out)
99{ 99{
100 uint8_t rndsts; 100 uint8_t rndsts;
101 101
102 /* 102 /*
103 * XXX The Intel DRNG SIG recommends (Sec. 5.2.1 `Retry 103 * XXX The Intel DRNG SIG recommends (Sec. 5.2.1 `Retry
104 * recommendations', p. 22) that we retry up to ten times 104 * recommendations', p. 22) that we retry up to ten times
105 * before giving up and panicking because something must be 105 * before giving up and panicking because something must be
106 * seriously awry with the CPU. 106 * seriously awry with the CPU.
107 * 107 *
108 * XXX The Intel DRNG SIG also recommends (Sec. 5.2.6 108 * XXX The Intel DRNG SIG also recommends (Sec. 5.2.6
109 * `Generating Seeds from RDRAND', p. 28) drawing 1024 64-bit 109 * `Generating Seeds from RDRAND', p. 28) drawing 1024 64-bit
110 * samples (or, 512 128-bit samples) in order to guarantee that 110 * samples (or, 512 128-bit samples) in order to guarantee that
111 * the CPU has drawn an independent sample from the physical 111 * the CPU has drawn an independent sample from the physical
112 * entropy source, since the AES CTR_DRBG behind RDRAND will be 112 * entropy source, since the AES CTR_DRBG behind RDRAND will be
113 * used to generate at most 511 128-bit samples before it is 113 * used to generate at most 511 128-bit samples before it is
114 * reseeded from the physical entropy source. It is unclear 114 * reseeded from the physical entropy source. It is unclear
115 * whether the same considerations about RDSEED starvation 115 * whether the same considerations about RDSEED starvation
116 * apply to this advice. 116 * apply to this advice.
117 */ 117 */
118 118
119#ifdef __i386__ 119#ifdef __i386__
120 uint32_t lo, hi; 120 uint32_t lo, hi;
121 121
122 __asm __volatile("rdrand %0; setc %1" : "=r"(lo), "=qm"(rndsts)); 122 __asm __volatile("rdrand %0; setc %1" : "=r"(lo), "=qm"(rndsts));
123 if (rndsts != 1) 123 if (rndsts != 1)
124 return 0; 124 return 0;
125 __asm __volatile("rdrand %0; setc %1" : "=r"(hi), "=qm"(rndsts)); 125 __asm __volatile("rdrand %0; setc %1" : "=r"(hi), "=qm"(rndsts));
126 126
127 *out = (uint64_t)lo | ((uint64_t)hi << 32); 127 *out = (uint64_t)lo | ((uint64_t)hi << 32);
128 explicit_memset(&lo, 0, sizeof(lo)); 128 explicit_memset(&lo, 0, sizeof(lo));
129 explicit_memset(&hi, 0, sizeof(hi)); 129 explicit_memset(&hi, 0, sizeof(hi));
130 if (rndsts != 1) 130 if (rndsts != 1)
131 return sizeof(lo) * NBBY; 131 return sizeof(lo) * NBBY;
132#else 132#else
133 __asm __volatile("rdrand %0; setc %1" : "=r"(*out), "=qm"(rndsts)); 133 __asm __volatile("rdrand %0; setc %1" : "=r"(*out), "=qm"(rndsts));
134 if (rndsts != 1) 134 if (rndsts != 1)
135 return 0; 135 return 0;
136#endif 136#endif
137 return sizeof(*out) * NBBY; 137 return sizeof(*out) * NBBY;
138} 138}
139 139
140static size_t 140static size_t
141cpu_rng_rdseed(uint64_t *out) 141cpu_rng_rdseed(uint64_t *out)
142{ 142{
143 uint8_t rndsts; 143 uint8_t rndsts;
144 144
145 /* 145 /*
146 * XXX The Intel DRNG SIG recommends (Sec. 5.3.1 `Retry 146 * XXX The Intel DRNG SIG recommends (Sec. 5.3.1 `Retry
147 * recommendations', p. 22) that we consider retrying up to 100 147 * recommendations', p. 22) that we consider retrying up to 100
148 * times, separated by PAUSE, but offers no guarantees about 148 * times, separated by PAUSE, but offers no guarantees about
149 * success after that many retries. In particular, userland 149 * success after that many retries. In particular, userland
150 * threads could starve the kernel by issuing RDSEED. 150 * threads could starve the kernel by issuing RDSEED.
151 */ 151 */
152 152
153#ifdef __i386__ 153#ifdef __i386__
154 uint32_t lo, hi; 154 uint32_t lo, hi;
155 155
156 __asm __volatile("rdseed %0; setc %1" : "=r"(lo), "=qm"(rndsts)); 156 __asm __volatile("rdseed %0; setc %1" : "=r"(lo), "=qm"(rndsts));
157 if (rndsts != 1) 157 if (rndsts != 1)
158 return 0; 158 return 0;
159 __asm __volatile("rdseed %0; setc %1" : "=r"(hi), "=qm"(rndsts)); 159 __asm __volatile("rdseed %0; setc %1" : "=r"(hi), "=qm"(rndsts));
160 if (rndsts != 1) 160 if (rndsts != 1)
161 return 0; 161 return 0;
162 162
163 *out = (uint64_t)lo | ((uint64_t)hi << 32); 163 *out = (uint64_t)lo | ((uint64_t)hi << 32);
164 explicit_memset(&lo, 0, sizeof(lo)); 164 explicit_memset(&lo, 0, sizeof(lo));
165 explicit_memset(&hi, 0, sizeof(hi)); 165 explicit_memset(&hi, 0, sizeof(hi));
166#else 166#else
167 __asm __volatile("rdseed %0; setc %1" : "=r"(*out), "=qm"(rndsts)); 167 __asm __volatile("rdseed %0; setc %1" : "=r"(*out), "=qm"(rndsts));
168#endif 168#endif
169 if (rndsts != 1) 169 if (rndsts != 1)
170 return 0; 170 return 0;
171 171
172 return sizeof(*out) * NBBY; 172 return sizeof(*out) * NBBY;
173} 173}
174 174
175static size_t 175static size_t
176cpu_rng_rdseed_rdrand(uint64_t *out) 176cpu_rng_rdseed_rdrand(uint64_t *out)
177{ 177{
178 size_t n = cpu_rng_rdseed(out); 178 size_t n = cpu_rng_rdseed(out);
179 179
180 if (n == 0) 180 if (n == 0)
181 n = cpu_rng_rdrand(out); 181 n = cpu_rng_rdrand(out);
182 182
183 return n; 183 return n;
184} 184}
185 185
186/* 186/*
187 * VIA PPG says EAX[4:0] is nbytes, but the only documented numbers of 187 * VIA PPG says EAX[4:0] is nbytes, but the only documented numbers of
188 * bytes are 0,1,2,4,8 -- and there's only 8 bytes of output buffer 188 * bytes are 0,1,2,4,8 -- and there's only 8 bytes of output buffer
189 * anyway, so let's ignore bit 4 and treat it like EAX[3:0] instead. 189 * anyway, so let's ignore bit 4 and treat it like EAX[3:0] instead.
190 */ 190 */
191#define VIA_RNG_STATUS_NBYTES __BITS(3,0) 191#define VIA_RNG_STATUS_NBYTES __BITS(3,0)
192#define VIA_RNG_STATUS_MSR110B __BITS(31,5) 192#define VIA_RNG_STATUS_MSR110B __BITS(31,5)
193 193
194static size_t 194static size_t
195cpu_rng_via(uint64_t *out) 195cpu_rng_via(uint64_t *out)
196{ 196{
197 u_long psl; 197 u_long psl;
198 uint32_t cr0, status, nbytes; 198 uint32_t cr0, status, nbytes;
199 199
200 /* 200 /*
201 * The XSTORE instruction is handled by the SSE unit, which 201 * The XSTORE instruction is handled by the SSE unit, which
202 * requires the CR0 TS and CR0 EM bits to be clear. We disable 202 * requires the CR0 TS and CR0 EM bits to be clear. We disable
203 * all processor interrupts so there is no danger of any 203 * all processor interrupts so there is no danger of any
204 * interrupt handler changing CR0 while we work -- although 204 * interrupt handler changing CR0 while we work -- although
205 * really, software splvm or fpu_kern_enter/leave should be 205 * really, software splvm or fpu_kern_enter/leave should be
206 * enough (but we'll do that in a separate change for the 206 * enough (but we'll do that in a separate change for the
207 * benefit of bisection in case I'm wrong). 207 * benefit of bisection in case I'm wrong).
208 */ 208 */
209 psl = x86_read_psl(); 209 psl = x86_read_psl();
210 x86_disable_intr(); 210 x86_disable_intr();
211 cr0 = rcr0(); 211 cr0 = rcr0();
212 lcr0(cr0 & ~(CR0_EM|CR0_TS)); 212 lcr0(cr0 & ~(CR0_EM|CR0_TS));
213 213
214 /* Read up to eight bytes out of the buffer. */ 214 /* Read up to eight bytes out of the buffer. */
215 asm volatile("xstorerng" 215 asm volatile("xstorerng"
216 : "=a"(status) 216 : "=a"(status)
217 : "D"(out), "d"(0) /* EDX[1:0]=00 -> wait for 8 bytes or fail */ 217 : "D"(out), "d"(0) /* EDX[1:0]=00 -> wait for 8 bytes or fail */
218 : "memory"); 218 : "memory");
219 219
220 /* Restore CR0 and interrupts. */ 220 /* Restore CR0 and interrupts. */
221 lcr0(cr0); 221 lcr0(cr0);
222 x86_write_psl(psl); 222 x86_write_psl(psl);
223 223
224 /* Get the number of bytes stored. (Should always be 8 or 0.) */ 224 /* Get the number of bytes stored. (Should always be 8 or 0.) */
225 nbytes = __SHIFTOUT(status, VIA_RNG_STATUS_NBYTES); 225 nbytes = __SHIFTOUT(status, VIA_RNG_STATUS_NBYTES);
226 226
227 /* 227 /*
228 * The Cryptography Research paper on the VIA RNG estimates 228 * The Cryptography Research paper on the VIA RNG estimates
229 * 0.75 bits of entropy per output bit and advises users to 229 * 0.75 bits of entropy per output bit and advises users to
230 * be "even more conservative". 230 * be "even more conservative".
 231 *
 232 * `Evaluation of VIA C3 Nehemiah Random Number
 233 * Generator', Cryptography Research, Inc., February 27,
 234 * 2003.
 235 * https://www.rambus.com/wp-content/uploads/2015/08/VIA_rng.pdf
231 */ 236 */
232 return nbytes * NBBY/2; 237 return nbytes * NBBY/2;
233} 238}
234 239
235static size_t 240static size_t
236cpu_rng(enum cpu_rng_mode mode, uint64_t *out) 241cpu_rng(enum cpu_rng_mode mode, uint64_t *out)
237{ 242{
238 243
239 switch (mode) { 244 switch (mode) {
240 case CPU_RNG_NONE: 245 case CPU_RNG_NONE:
241 return 0; 246 return 0;
242 case CPU_RNG_RDSEED: 247 case CPU_RNG_RDSEED:
243 return cpu_rng_rdseed(out); 248 return cpu_rng_rdseed(out);
244 case CPU_RNG_RDRAND: 249 case CPU_RNG_RDRAND:
245 return cpu_rng_rdrand(out); 250 return cpu_rng_rdrand(out);
246 case CPU_RNG_RDSEED_RDRAND: 251 case CPU_RNG_RDSEED_RDRAND:
247 return cpu_rng_rdseed_rdrand(out); 252 return cpu_rng_rdseed_rdrand(out);
248 case CPU_RNG_VIA: 253 case CPU_RNG_VIA:
249 return cpu_rng_via(out); 254 return cpu_rng_via(out);
250 default: 255 default:
251 panic("cpu_rng: unknown mode %d", (int)mode); 256 panic("cpu_rng: unknown mode %d", (int)mode);
252 } 257 }
253} 258}
254 259
255static void 260static void
256cpu_rng_get(size_t nbytes, void *cookie) 261cpu_rng_get(size_t nbytes, void *cookie)
257{ 262{
258#define N howmany(256, 64) 263#define N howmany(256, 64)
259 uint64_t buf[2*N]; 264 uint64_t buf[2*N];
260 unsigned i, nbits = 0; 265 unsigned i, nbits = 0;
261 266
262 while (nbytes) { 267 while (nbytes) {
263 /* 268 /*
264 * The fraction of outputs this rejects in correct 269 * The fraction of outputs this rejects in correct
265 * operation is 1/2^256, which is close enough to zero 270 * operation is 1/2^256, which is close enough to zero
266 * that we round it to having no effect on the number 271 * that we round it to having no effect on the number
267 * of bits of entropy. 272 * of bits of entropy.
268 */ 273 */
269 for (i = 0; i < __arraycount(buf); i++) 274 for (i = 0; i < __arraycount(buf); i++)
270 nbits += cpu_rng(cpu_rng_mode, &buf[i]); 275 nbits += cpu_rng(cpu_rng_mode, &buf[i]);
271 if (consttime_memequal(buf, buf + N, N)) { 276 if (consttime_memequal(buf, buf + N, N)) {
272 printf("cpu_rng %s: failed repetition test\n", 277 printf("cpu_rng %s: failed repetition test\n",
273 cpu_rng_name[cpu_rng_mode]); 278 cpu_rng_name[cpu_rng_mode]);
274 nbits = 0; 279 nbits = 0;
275 } 280 }
276 rnd_add_data_sync(&cpu_rng_source, buf, sizeof buf, nbits); 281 rnd_add_data_sync(&cpu_rng_source, buf, sizeof buf, nbits);
277 nbytes -= MIN(MIN(nbytes, sizeof buf), MAX(1, 8*nbits)); 282 nbytes -= MIN(MIN(nbytes, sizeof buf), MAX(1, 8*nbits));
278 } 283 }
279#undef N 284#undef N
280} 285}
281 286
282void 287void
283cpu_rng_init(void) 288cpu_rng_init(void)
284{ 289{
285 290
286 cpu_rng_mode = cpu_rng_detect(); 291 cpu_rng_mode = cpu_rng_detect();
287 if (cpu_rng_mode == CPU_RNG_NONE) 292 if (cpu_rng_mode == CPU_RNG_NONE)
288 return; 293 return;
289 aprint_normal("cpu_rng: %s\n", cpu_rng_name[cpu_rng_mode]); 294 aprint_normal("cpu_rng: %s\n", cpu_rng_name[cpu_rng_mode]);
290 rndsource_setcb(&cpu_rng_source, cpu_rng_get, NULL); 295 rndsource_setcb(&cpu_rng_source, cpu_rng_get, NULL);
291 rnd_attach_source(&cpu_rng_source, cpu_rng_name[cpu_rng_mode], 296 rnd_attach_source(&cpu_rng_source, cpu_rng_name[cpu_rng_mode],
292 RND_TYPE_RNG, RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB); 297 RND_TYPE_RNG, RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB);
293} 298}
294 299
295/* -------------------------------------------------------------------------- */ 300/* -------------------------------------------------------------------------- */
296 301
297void 302void
298cpu_rng_early_sample(uint64_t *sample) 303cpu_rng_early_sample(uint64_t *sample)
299{ 304{
300 static bool has_rdseed = false; 305 static bool has_rdseed = false;
301 static bool has_rdrand = false; 306 static bool has_rdrand = false;
302 static bool inited = false; 307 static bool inited = false;
303 u_int descs[4]; 308 u_int descs[4];
304 size_t n; 309 size_t n;
305 310
306 if (!inited) { 311 if (!inited) {
307 if (cpuid_level >= 7) { 312 if (cpuid_level >= 7) {
308 x86_cpuid(0x07, descs); 313 x86_cpuid(0x07, descs);
309 has_rdseed = (descs[1] & CPUID_SEF_RDSEED) != 0; 314 has_rdseed = (descs[1] & CPUID_SEF_RDSEED) != 0;
310 } 315 }
311 if (cpuid_level >= 1) { 316 if (cpuid_level >= 1) {
312 x86_cpuid(0x01, descs); 317 x86_cpuid(0x01, descs);
313 has_rdrand = (descs[2] & CPUID2_RDRAND) != 0; 318 has_rdrand = (descs[2] & CPUID2_RDRAND) != 0;
314 } 319 }
315 inited = true; 320 inited = true;
316 } 321 }
317 322
318 n = 0; 323 n = 0;
319 if (has_rdseed && has_rdrand) 324 if (has_rdseed && has_rdrand)
320 n = cpu_rng_rdseed_rdrand(sample); 325 n = cpu_rng_rdseed_rdrand(sample);
321 else if (has_rdseed) 326 else if (has_rdseed)
322 n = cpu_rng_rdseed(sample); 327 n = cpu_rng_rdseed(sample);
323 else if (has_rdrand) 328 else if (has_rdrand)
324 n = cpu_rng_rdrand(sample); 329 n = cpu_rng_rdrand(sample);
325 if (n == 0) 330 if (n == 0)
326 *sample = rdtsc(); 331 *sample = rdtsc();
327} 332}