xref: /illumos-gate/usr/src/uts/sun4v/io/n2rng/n2rng_entp_setup.c (revision fbd1c0dae6f4a2ccc2ce0527c7f19d3dd5ea90b8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/sysmacros.h>
30 #include <sys/modctl.h>
31 #include <sys/conf.h>
32 #include <sys/devops.h>
33 #include <sys/cmn_err.h>
34 #include <sys/kmem.h>
35 #include <sys/stat.h>
36 #include <sys/open.h>
37 #include <sys/file.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40 #include <sys/cpuvar.h>
41 #include <sys/disp.h>
42 #include <sys/hsvc.h>
43 #include <sys/machsystm.h>
44 #include <sys/param.h>
45 #include <sys/hypervisor_api.h>
46 #include <sys/n2rng.h>
47 
48 /*
49  * There are 3 noise cells each with its own oscillator, and each
50  * oscillator can be set to 4 different bias setttings.  The bias
51  * setting controls the nominal frequency of the oscillator.  The 3
52  * and 4 and hardcoded throughout this file.
53  */
54 
55 #define	BITS_IN(type) (8 * sizeof (type))
56 #define	EXTRACTBIT64(val, bit) (((val) >> (bit)) & 1UL)
57 
58 /*
59  * Policy settings
60  */
61 /* Log2 of the number of bits */
62 #define	SETTLECYCLES		1000000
63 #define	NORMAL_BYPASS		1
64 #define	NUMOSC			3
65 #define	LOG2_DATA_WORDS		15
66 #define	DATA_WORDS		(1 << LOG2_DATA_WORDS)
67 
68 #define	ENTROPY_PASS_VALUE	150000000ULL
69 
70 /*
71  * There is a hardware bug that causes the RNG_DATA register to
72  * occasionally be read one cycle before the specifed time.
73  * LOGIC_TEST_EXPECTED_M1 is the value one cycle before
74  * LOGIC_TEST_CYCLES.  And there is a second bug that causes the read
75  * to be delayed.  We have seen delays of about 150 cycles, but do not
76  * know that maximum that could possibly occur.
77  *
78  * We collect LOGIC_TEST_WORDS words using a diagnostic read with all
79  * entropy turned off.  The first one we skip, becuase we have no
80  * knowledge of the time since the last read.  We check that the
81  * remaining values fall in the window of values that should occur
82  * between LOGIC_TEST_CYCLES - 1 and LOGIC_TEST_CYCLES +
83  * LOGIC_TEST_BUG_MAX.  As further protecion against false positives,
84  * we report success if the the number of mismatches does not exceed
85  * LOGIC_TEST_ERRORS_ALLOWED.
86  */
87 
88 #define	LOGIC_TEST_CYCLES	38859
89 #define	LOGIC_TEST_EXPECTED_M1	0xb8820c7bd387e32cULL
90 #define	LOGIC_TEST_BUG_MAX	400
91 #define	LOGIC_TEST_WORDS	8 /* includes first one, unused */
92 #define	LOGIC_TEST_ERRORS_ALLOWED 1
93 #define	RNG_POLY		0x231dcee91262b8a3ULL
94 #define	ENTDIVISOR		(((1ULL << LOG_VAL_SCALE) + 500ULL) / 1000ULL)
95 
96 #define	ENCODEBIAS(osc, bias)	(((bias) & 0x3) << (2 * (osc)))
97 #define	EXTRACTBIAS(blob, osc)	(((blob) >> (2 * (osc))) & 0x3)
98 
99 extern int n2rng_herr2kerr(uint64_t hv_errcode);
100 
101 
102 /*
103  * Each value is a representation of the polynomail bit_i * x^i, where
104  * i=0 corresponds to the least significant bit of the word.  The
105  * modulus polynomial is x^64 + the interpretation of poly.  Out is
106  * set to in * x^exp mod moduluspolynomial.  This corresponds to
107  * running the LFSR exp cycles.  This implemenation directly simulates
108  * the lfsr.  It's running time is O(exp), but the constant is small.
109  * (This code was taken verbatim from Legion.)
110  */
111 static void
112 lfsr64_adv_seq(uint64_t poly, uint64_t in, uint64_t exp, uint64_t *out)
113 {
114 	int		i;
115 	uint64_t	res = in;
116 
117 	for (i = 0; i < exp; i++) {
118 		if (res & 0x8000000000000000ULL) {
119 			res = (res << 1) ^ poly;
120 		} else {
121 			res <<= 1;
122 		}
123 	}
124 
125 	*out = res;
126 }
127 
128 
129 int
130 n2rng_logic_test(n2rng_t *n2rng)
131 {
132 	n2rng_setup_t	logictest;
133 	uint64_t	buffer[2];
134 	uint64_t	reg;
135 	int		rv;
136 	int		i, j;
137 	int		correctcount = 0;
138 
139 	/*
140 	 * This test runs the RNG with no entropy for
141 	 * LOGIC_TEST_CYCLES cycles.  Ideally the value would be be
142 	 * LOGIC_TEST_RESULT, but because of the RNG bug, the actual
143 	 * register read may be delayed by upto LOGIC_TEST_BUG_MAX
144 	 * cycles.  So we simulate over that window, and a match
145 	 * occurs, we report success.
146 	 */
147 
148 	logictest.ctlwds[0].word = 0;
149 	logictest.ctlwds[0].fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
150 	logictest.ctlwds[1] = logictest.ctlwds[0];
151 	logictest.ctlwds[2] = logictest.ctlwds[0];
152 	logictest.ctlwds[3] = logictest.ctlwds[0];
153 	logictest.ctlwds[3].fields.rnc_mode = 1;
154 	logictest.ctlwds[3].fields.rnc_cnt = LOGIC_TEST_CYCLES - 2;
155 
156 	/* read LOGIC_TEST_WORDS 64-bit words */
157 
158 
159 	rv = n2rng_collect_diag_bits(n2rng, &logictest, buffer,
160 	    LOGIC_TEST_WORDS * sizeof (uint64_t),
161 	    &n2rng->n_preferred_config, n2rng->n_rng_state);
162 	if (rv) {
163 		cmn_err(CE_WARN,
164 		    "n2rng: n2rng_collect_diag_bits fails with 0x%x", rv);
165 		return (rv);
166 	}
167 
168 	reg = LOGIC_TEST_EXPECTED_M1;
169 	for (i = 0; i <= LOGIC_TEST_BUG_MAX; i++) {
170 		for (j = 1; j < LOGIC_TEST_WORDS; ++j) {
171 			if (buffer[j] == reg) {
172 				++correctcount;
173 			}
174 		}
175 		/* advance reg by one step */
176 		lfsr64_adv_seq(RNG_POLY, reg, 1, &reg);
177 	}
178 
179 	if (correctcount < LOGIC_TEST_WORDS - 1 - LOGIC_TEST_ERRORS_ALLOWED) {
180 		cmn_err(CE_WARN, "n2rng: logic error in rng.");
181 		return (EIO);
182 	}
183 
184 	return (0);
185 }
186 
187 
188 /*
189  * gets the metric for the specified state.
190  */
191 int
192 n2rng_collect_metrics(n2rng_t *n2rng, n2rng_setup_t *setupp,
193     n2rng_setup_t *exit_setupp,
194     uint64_t exit_state, n2rng_osc_perf_t *metricp)
195 {
196 	int		rv;
197 	int		bufsize;
198 	uint64_t	*buffer = NULL;
199 
200 
201 	bufsize = DATA_WORDS * sizeof (uint64_t);
202 	buffer = (uint64_t *)contig_mem_alloc_align(bufsize,
203 	    CONTIG_ALIGNMENT);
204 	if (buffer == NULL) {
205 		return (ENOMEM);
206 	}
207 
208 	rv = n2rng_collect_diag_bits(n2rng, setupp, buffer, bufsize,
209 	    exit_setupp, exit_state);
210 	if (rv) {
211 		cmn_err(CE_WARN,
212 		    "n2rng: n2rng_collect_bits returns 0x%x", rv);
213 	} else {
214 		n2rng_renyi_entropy(buffer, LOG2_DATA_WORDS, metricp);
215 	}
216 
217 	contig_mem_free(buffer, bufsize);
218 
219 	return (rv);
220 }
221 
222 
223 /*
224  * Fills in table with the performance of each oscillator at each
225  * bias setting.  A particular datum goes in table[osc][bias].
226  */
227 int
228 collect_rng_perf(n2rng_t *n2rng, n2rng_osc_perf_table_t ptable)
229 {
230 	int		bias;
231 	int		osc;
232 	n2rng_setup_t	rngstate;
233 	int		rv;
234 
235 	rngstate.ctlwds[0].word = 0;
236 	rngstate.ctlwds[0].fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
237 	rngstate.ctlwds[1] = rngstate.ctlwds[0];
238 	rngstate.ctlwds[2] = rngstate.ctlwds[0];
239 	rngstate.ctlwds[3] = rngstate.ctlwds[0];
240 
241 	for (osc = 0; osc < N2RNG_NOSC; osc++) {
242 		rngstate.ctlwds[3].fields.rnc_selbits = 1 << osc;
243 		for (bias = 0; bias < N2RNG_NBIASES; bias++) {
244 			rngstate.ctlwds[3].fields.rnc_vcoctl = bias;
245 			rv = n2rng_collect_metrics(n2rng, &rngstate,
246 			    &n2rng->n_preferred_config,
247 			    n2rng->n_rng_state,
248 			    &(ptable[osc][bias]));
249 			if (rv) {
250 				return (rv);
251 			}
252 		}
253 	}
254 
255 	return (rv);
256 }
257 
258 
259 
260 /*
261  * The following 2 functions test the performance of each noise cell
262  * and select the bias settings.  They implement the following
263  * policies:
264  *
265  * 1. No two cells may be set to the same bias. (Cells with the same bias,
266  *    which controls frequency, may beat together, with long
267  *    runs of no entropy as a pair when they are nearly synchronized.)
268  * 2. The entropy of each cell is determined (for now) by the Renyi H2
269  *    entropy of a collection of samples of raw bits.
270  * 3. The selected configuration is the one that has the largest total
271  *    entropy, computed as stated above.
272  * 4. The delay is hard coded.
273  */
274 
275 
276 /*
277  * Finds the preferred configuration from perf data.  Sets the
278  * preferred configuration in the n2rng structure.
279  */
280 int
281 n2rng_noise_gen_preferred(n2rng_t *n2rng)
282 {
283 	int			rv;
284 	int			rventropy = 0; /* EIO if entropy is too low */
285 	int			b0, b1, b2;
286 	int			osc;
287 	int			bset;
288 	n2rng_osc_perf_t	*candidates[N2RNG_NOSC];
289 	uint64_t		bestcellentropy[N2RNG_NOSC] = {0};
290 	uint64_t		bestentropy = 0;
291 	n2rng_ctl_t		rng_ctl = {0};
292 	int			i;
293 
294 	rv = collect_rng_perf(n2rng, n2rng->n_perftable);
295 	if (rv) {
296 		return (rv);
297 	}
298 
299 	/*
300 	 * bset is the bias setting of all 3 oscillators packed into a
301 	 * word, 2 bits for each: b2:b1:b0.  First we set up an
302 	 * arbitrary assignement, because in an earlier version of
303 	 * this code, there were cases where the assignment would
304 	 * never happen.  Also, that way we don't need to prove
305 	 * assignment to prove we never have uninitalized variables,
306 	 * and hence it might avoid lint warnings.
307 	 *
308 	 * This block of code picks the "best" setting of the biases,
309 	 * where "best" is defined by the rules in the big comment
310 	 * block above.
311 	 *
312 	 * There are only 24 possible combinations such that no two
313 	 * oscillators get the same bias.  We just do a brute force
314 	 * exhaustive search of the entire space.
315 	 */
316 	bset = ENCODEBIAS(2, 2) | ENCODEBIAS(1, 1) | ENCODEBIAS(0, 0);
317 	for (b0 = 0; b0 < N2RNG_NBIASES; b0++) {
318 		candidates[0] = &n2rng->n_perftable[0][b0];
319 		for (b1 = 0; b1 < N2RNG_NBIASES; b1++) {
320 			if (b0 == b1) continue;
321 			candidates[1] = &n2rng->n_perftable[1][b1];
322 			for (b2 = 0; b2 < N2RNG_NBIASES; b2++) {
323 				uint64_t totalentropy = 0;
324 
325 				if (b0 == b2 || b1 == b2) continue;
326 				candidates[2] = &n2rng->n_perftable[2][b2];
327 				for (i = 0; i < N2RNG_NOSC; i++) {
328 					totalentropy += candidates[i]->H2;
329 				}
330 				if (totalentropy > bestentropy) {
331 					bestentropy = totalentropy;
332 					bset = ENCODEBIAS(0, b0) |
333 					    ENCODEBIAS(1, b1) |
334 					    ENCODEBIAS(2, b2);
335 					for (i = 0; i < N2RNG_NOSC; i++) {
336 						bestcellentropy[i] =
337 						    candidates[i]->H2;
338 					}
339 
340 				}
341 
342 			}
343 		}
344 	}
345 
346 	if (bestentropy < ENTROPY_PASS_VALUE) {
347 		cmn_err(CE_WARN,
348 		    "n2rng: RNG hardware producing insufficient "
349 		    "entropy (producing %ld, need %lld)",
350 		    bestentropy, ENTROPY_PASS_VALUE);
351 		rventropy = EIO;
352 	}
353 
354 	/*
355 	 * Set up fields of control words that will be the same for all
356 	 * osciallators and for final value that selects all
357 	 * oscillators.
358 	 */
359 	rng_ctl.fields.rnc_cnt = RNG_DEFAULT_ACCUMULATE_CYCLES;
360 	rng_ctl.fields.rnc_mode = 1;  /* set normal mode */
361 	rng_ctl.fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
362 
363 
364 	/*
365 	 * Now set the oscillator biases.
366 	 */
367 	for (osc = 0; osc < N2RNG_NOSC; osc++) {
368 		rng_ctl.fields.rnc_selbits = 1 << osc;
369 		rng_ctl.fields.rnc_vcoctl = EXTRACTBIAS(bset, osc);
370 		n2rng->n_preferred_config.ctlwds[osc] = rng_ctl;
371 	}
372 
373 	rng_ctl.fields.rnc_cnt = RNG_DEFAULT_ACCUMULATE_CYCLES;
374 	rng_ctl.fields.rnc_vcoctl = 0;
375 	rng_ctl.fields.rnc_selbits = 0x7;
376 	n2rng->n_preferred_config.ctlwds[3] = rng_ctl;
377 
378 	/*
379 	 * Log the entropy and bias setting for the admin and security
380 	 * auditors.
381 	 */
382 	if (rventropy == 0) {
383 		cmn_err(CE_NOTE,
384 		    "!n2rng: RNG passes, "
385 		    "cell 0 bias %d: %ld, "
386 		    "cell 1 bias %d: %ld, "
387 		    "cell 2 bias %d: %ld",
388 		    EXTRACTBIAS(bset, 0),
389 		    (uint64_t)(bestcellentropy[0] / ENTDIVISOR),
390 		    EXTRACTBIAS(bset, 1),
391 		    (uint64_t)(bestcellentropy[1] / ENTDIVISOR),
392 		    EXTRACTBIAS(bset, 2),
393 		    (uint64_t)(bestcellentropy[2] / ENTDIVISOR));
394 
395 	}
396 
397 	return (rv ? rv : rventropy);
398 }
399 
400 
401 
402 /*
403  * Do a logic test, then find and set the best bias confuration
404  * (failing if insufficient entropy is generated, then set state to
405  * configured.
406  */
407 int
408 n2rng_do_health_check(n2rng_t *n2rng)
409 {
410 	int		rv;
411 	int		hverr;
412 
413 	/* Take control of RNG */
414 	do {
415 		hverr = hv_rng_get_diag_control();
416 		rv = n2rng_herr2kerr(hverr);
417 	} while (hverr == H_EWOULDBLOCK);
418 
419 	if (hverr)
420 		return (rv);
421 
422 	rv = n2rng_logic_test(n2rng);
423 	if (rv) {
424 		return (rv);
425 	}
426 
427 	rv = n2rng_noise_gen_preferred(n2rng);
428 	if (rv) {
429 		return (rv);
430 	}
431 
432 	/* Push the selected config into HW */
433 	rv = n2rng_collect_diag_bits(n2rng, NULL, NULL, 0,
434 	    &n2rng->n_preferred_config, CTL_STATE_CONFIGURED);
435 	if (rv) {
436 		return (rv);
437 	}
438 
439 	n2rng->n_rng_state = CTL_STATE_CONFIGURED;
440 
441 	return (rv);
442 }
443