/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/sysmacros.h>
#include <sys/machsystm.h>
#include <sys/hypervisor_api.h>
/*
* There are 3 noise cells each with its own oscillator, and each
* oscillator can be set to 4 different bias setttings. The bias
* setting controls the nominal frequency of the oscillator. The 3
* and 4 and hardcoded throughout this file.
*/
/*
* Policy settings
*/
/* Log2 of the number of bits */
/*
* There is a hardware bug that causes the RNG_DATA register to
* occasionally be read one cycle before the specifed time.
* LOGIC_TEST_EXPECTED_M1 is the value one cycle before
* LOGIC_TEST_CYCLES. And there is a second bug that causes the read
* to be delayed. We have seen delays of about 150 cycles, but do not
* know that maximum that could possibly occur.
*
* We collect LOGIC_TEST_WORDS words using a diagnostic read with all
* entropy turned off. The first one we skip, becuase we have no
* knowledge of the time since the last read. We check that the
* remaining values fall in the window of values that should occur
* between LOGIC_TEST_CYCLES - 1 and LOGIC_TEST_CYCLES +
* LOGIC_TEST_BUG_MAX. As further protecion against false positives,
* we report success if the the number of mismatches does not exceed
* LOGIC_TEST_ERRORS_ALLOWED.
*
* When running on maramba systems, delays as high as 20000 were observed
* LOGIC_TEST_BUG_MAX was increased to twice this observed value since all
* that matters is that the hardware is indeed generating the expected values
* in diag mode. The code was also modified to exit as soon as the required
* number of matches is detected.
*/
/*
* Each value is a representation of the polynomail bit_i * x^i, where
* i=0 corresponds to the least significant bit of the word. The
* modulus polynomial is x^64 + the interpretation of poly. Out is
* set to in * x^exp mod moduluspolynomial. This corresponds to
* running the LFSR exp cycles. This implemenation directly simulates
* the lfsr. It's running time is O(exp), but the constant is small.
* (This code was taken verbatim from Legion.)
*/
static void
{
int i;
for (i = 0; i < exp; i++) {
if (res & 0x8000000000000000ULL) {
} else {
res <<= 1;
}
}
}
int
{
int rv;
int i, j;
int correctcount = 0;
{0, 0, 0, 0, 0, 0, 0, 0};
/*
* This test runs the RNG with no entropy for
* LOGIC_TEST_CYCLES cycles. Ideally the value would be be
* LOGIC_TEST_RESULT, but because of the RNG bug, the actual
* register read may be delayed by upto LOGIC_TEST_BUG_MAX
* cycles. So we simulate over that window, and a match
* occurs, we report success.
*/
/* read LOGIC_TEST_WORDS 64-bit words */
LOGIC_TEST_WORDS * sizeof (uint64_t),
if (rv) {
return (rv);
}
for (i = 0; i <= LOGIC_TEST_BUG_MAX; i++) {
for (j = 1; j < LOGIC_TEST_WORDS; ++j) {
++correctcount;
cycles[j] = i;
}
}
/* exit loop if we have already found enough matches */
if (correctcount >= LOGIC_TEST_MATCHES_NEEDED) {
break;
}
/* advance reg by one step */
}
if (correctcount < LOGIC_TEST_MATCHES_NEEDED) {
/*
* Don't log a warning here since the calling routine will
* retry and log it's own warning if the retry fails.
*/
for (i = 0; i < LOGIC_TEST_WORDS; i++) {
}
return (EIO);
} else {
for (i = 0; i < LOGIC_TEST_WORDS; i++) {
}
}
return (0);
}
/*
* gets the metric for the specified state.
*/
int
{
int rv;
int bufsize;
return (ENOMEM);
}
if (rv) {
"n2rng: n2rng_collect_bits returns 0x%x", rv);
} else {
}
return (rv);
}
/*
* Fills in table with the performance of each oscillator at each
* bias setting. A particular datum goes in table[osc][bias].
*/
int
{
int bias;
int osc;
int rv;
if (rv) {
return (rv);
}
}
}
return (rv);
}
/*
* The following 2 functions test the performance of each noise cell
* and select the bias settings. They implement the following
* policies:
*
* 1. No two cells may be set to the same bias. (Cells with the same bias,
* which controls frequency, may beat together, with long
* runs of no entropy as a pair when they are nearly synchronized.)
* 2. The entropy of each cell is determined (for now) by the Renyi H2
* entropy of a collection of samples of raw bits.
* 3. The selected configuration is the one that has the largest total
* entropy, computed as stated above.
* 4. The delay is hard coded.
*/
/*
* Finds the preferred configuration from perf data. Sets the
* preferred configuration in the n2rng structure.
*/
int
{
int rv;
int osc;
int bset;
int i;
if (rv) {
return (rv);
}
/*
* bset is the bias setting of all 3 oscillators packed into a
* word, 2 bits for each: b2:b1:b0. First we set up an
* arbitrary assignment, because in an earlier version of
* this code, there were cases where the assignment would
* never happen. Also, that way we don't need to prove
* assignment to prove we never have uninitalized variables,
* and hence it might avoid lint warnings.
*
* This block of code picks the "best" setting of the biases,
* where "best" is defined by the rules in the big comment
* block above.
*
* There are only 24 possible combinations such that no two
* oscillators get the same bias. We just do a brute force
* exhaustive search of the entire space.
*/
for (i = 0; i < N2RNG_NOSC; i++) {
}
if (totalentropy > bestentropy) {
for (i = 0; i < N2RNG_NOSC; i++) {
bestcellentropy[i] =
candidates[i]->H2;
}
}
}
}
}
if (bestentropy < ENTROPY_PASS_VALUE) {
"n2rng: RNG hardware producing insufficient "
"entropy (producing %ld, need %lld)",
}
/*
* Set up fields of control words that will be the same for all
* osciallators and for final value that selects all
* oscillators.
*/
/*
* Now set the oscillator biases.
*/
}
if (rventropy == 0) {
/* Save bias and entropy results for kstats */
for (i = 0; i < N2RNG_NOSC; i++) {
"n2rng_noise_gen_preferred: rng %d cell %d bias "
}
} else {
/* Clear bias and entropy results for kstats */
for (i = 0; i < N2RNG_NOSC; i++) {
}
}
}
/*
* Do a logic test, then find and set the best bias confuration
* (failing if insufficient entropy is generated, then set state to
* configured. This function should only be called when running in
* the control domain.
*/
int
{
int attempts;
for (attempts = 0;
}
if (rv) {
goto errorexit;
} else if (attempts > 1) {
"n2rng: n2rng_logic_test failed %d attempts",
attempts - 1);
goto errorexit;
}
if (rv) {
"n2rng: n2rng_noise_gen_preferred failed");
goto errorexit;
}
/* Push the selected config into HW */
if (rv) {
"n2rng: n2rng_collect_diag_bits failed");
goto errorexit;
}
return (rv);
/* Push the selected config into HW with an error state */
return (rv);
}