| @@ -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 | |
61 | static enum cpu_rng_mode { | | 61 | static 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 | |
69 | static const char *const cpu_rng_name[] = { | | 69 | static 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 | |
76 | static struct krndsource cpu_rng_source __read_mostly; | | 76 | static struct krndsource cpu_rng_source __read_mostly; |
77 | | | 77 | |
78 | static enum cpu_rng_mode | | 78 | static enum cpu_rng_mode |
79 | cpu_rng_detect(void) | | 79 | cpu_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 | |
97 | static size_t | | 97 | static size_t |
98 | cpu_rng_rdrand(uint64_t *out) | | 98 | cpu_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 | |
140 | static size_t | | 140 | static size_t |
141 | cpu_rng_rdseed(uint64_t *out) | | 141 | cpu_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 | |
175 | static size_t | | 175 | static size_t |
176 | cpu_rng_rdseed_rdrand(uint64_t *out) | | 176 | cpu_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 | |
194 | static size_t | | 194 | static size_t |
195 | cpu_rng_via(uint64_t *out) | | 195 | cpu_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 | |
235 | static size_t | | 240 | static size_t |
236 | cpu_rng(enum cpu_rng_mode mode, uint64_t *out) | | 241 | cpu_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 | |
255 | static void | | 260 | static void |
256 | cpu_rng_get(size_t nbytes, void *cookie) | | 261 | cpu_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 | |
282 | void | | 287 | void |
283 | cpu_rng_init(void) | | 288 | cpu_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 | |
297 | void | | 302 | void |
298 | cpu_rng_early_sample(uint64_t *sample) | | 303 | cpu_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 | } |