n2rng_entp_setup.c revision fec509a05ddbf645268fe2e537314def7d1b67c8
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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 */
#define SETTLECYCLES 1000000
#define NORMAL_BYPASS 1
#define NUMOSC 3
#define LOG2_DATA_WORDS 15
#define ENTROPY_PASS_VALUE 150000000ULL
/*
* 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.
*/
#define LOGIC_TEST_CYCLES 38859
#define LOGIC_TEST_EXPECTED_M1 0xb8820c7bd387e32cULL
#define LOGIC_TEST_BUG_MAX 400
#define LOGIC_TEST_ERRORS_ALLOWED 1
#define RNG_POLY 0x231dcee91262b8a3ULL
/*
* 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;
/*
* 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) {
"n2rng: n2rng_collect_diag_bits fails with 0x%x", rv);
return (rv);
}
for (i = 0; i <= LOGIC_TEST_BUG_MAX; i++) {
for (j = 1; j < LOGIC_TEST_WORDS; ++j) {
++correctcount;
}
}
/* advance reg by one step */
}
return (EIO);
}
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 rventropy = 0; /* EIO if entropy is too low */
int osc;
int bset;
uint64_t bestentropy = 0;
n2rng_ctl_t rng_ctl = {0};
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 assignement, 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.
*/
uint64_t totalentropy = 0;
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.
*/
}
/*
* Log the entropy and bias setting for the admin and security
* auditors.
*/
if (rventropy == 0) {
"!n2rng: RNG passes, "
"cell 0 bias %d: %ld, "
"cell 1 bias %d: %ld, "
"cell 2 bias %d: %ld",
EXTRACTBIAS(bset, 0),
}
}
/*
* Do a logic test, then find and set the best bias confuration
* (failing if insufficient entropy is generated, then set state to
* configured.
*/
int
{
int rv;
int hverr;
/* Take control of RNG */
do {
} while (hverr == H_EWOULDBLOCK);
if (hverr)
return (rv);
if (rv) {
return (rv);
}
if (rv) {
return (rv);
}
/* Push the selected config into HW */
if (rv) {
return (rv);
}
return (rv);
}