Enable rp235x trng self-tests by default
Gracefully handle rp235x trng self-test errors and resets
This commit is contained in:
parent
9ab6100577
commit
cdef573f52
@ -78,6 +78,9 @@ impl From<InverterChainLength> for u8 {
|
|||||||
/// failed entropy checks.
|
/// failed entropy checks.
|
||||||
/// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or
|
/// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or
|
||||||
/// 1 and sample count settings of 20-25.
|
/// 1 and sample count settings of 20-25.
|
||||||
|
/// Larger sample count settings (e.g. 100) provide proportionately slower average generation times. These settings
|
||||||
|
/// significantly reduce, but do not eliminate NIST test failures and entropy check failures. Results occasionally take an
|
||||||
|
/// especially long time to generate.
|
||||||
///
|
///
|
||||||
/// ---
|
/// ---
|
||||||
///
|
///
|
||||||
@ -108,9 +111,10 @@ pub struct Config {
|
|||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Config {
|
Config {
|
||||||
disable_autocorrelation_test: true,
|
// WARNING: Disabling these tests increases likelihood of poor rng results.
|
||||||
disable_crngt_test: true,
|
disable_autocorrelation_test: false,
|
||||||
disable_von_neumann_balancer: true,
|
disable_crngt_test: false,
|
||||||
|
disable_von_neumann_balancer: false,
|
||||||
sample_count: 25,
|
sample_count: 25,
|
||||||
inverter_chain_length: InverterChainLength::One,
|
inverter_chain_length: InverterChainLength::One,
|
||||||
}
|
}
|
||||||
@ -148,6 +152,7 @@ impl Default for Config {
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct Trng<'d, T: Instance> {
|
pub struct Trng<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
|
config: Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 12.12.1. Overview
|
/// 12.12.1. Overview
|
||||||
@ -159,28 +164,12 @@ const TRNG_BLOCK_SIZE_BYTES: usize = TRNG_BLOCK_SIZE_BITS / 8;
|
|||||||
impl<'d, T: Instance> Trng<'d, T> {
|
impl<'d, T: Instance> Trng<'d, T> {
|
||||||
/// Create a new TRNG driver.
|
/// Create a new TRNG driver.
|
||||||
pub fn new(_trng: Peri<'d, T>, _irq: impl Binding<T::Interrupt, InterruptHandler<T>> + 'd, config: Config) -> Self {
|
pub fn new(_trng: Peri<'d, T>, _irq: impl Binding<T::Interrupt, InterruptHandler<T>> + 'd, config: Config) -> Self {
|
||||||
let regs = T::regs();
|
let trng = Trng {
|
||||||
|
phantom: PhantomData,
|
||||||
regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false));
|
config: config,
|
||||||
|
};
|
||||||
let trng_config_register = regs.trng_config();
|
trng.initialize_rng();
|
||||||
trng_config_register.write(|w| {
|
trng
|
||||||
w.set_rnd_src_sel(config.inverter_chain_length.clone().into());
|
|
||||||
});
|
|
||||||
|
|
||||||
let sample_count_register = regs.sample_cnt1();
|
|
||||||
sample_count_register.write(|w| {
|
|
||||||
*w = config.sample_count;
|
|
||||||
});
|
|
||||||
|
|
||||||
let debug_control_register = regs.trng_debug_control();
|
|
||||||
debug_control_register.write(|w| {
|
|
||||||
w.set_auto_correlate_bypass(config.disable_autocorrelation_test);
|
|
||||||
w.set_trng_crngt_bypass(config.disable_crngt_test);
|
|
||||||
w.set_vnc_bypass(config.disable_von_neumann_balancer)
|
|
||||||
});
|
|
||||||
|
|
||||||
Trng { phantom: PhantomData }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_rng(&self) {
|
fn start_rng(&self) {
|
||||||
@ -198,6 +187,29 @@ impl<'d, T: Instance> Trng<'d, T> {
|
|||||||
reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true));
|
reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn initialize_rng(&self) {
|
||||||
|
let regs = T::regs();
|
||||||
|
|
||||||
|
regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false));
|
||||||
|
|
||||||
|
let trng_config_register = regs.trng_config();
|
||||||
|
trng_config_register.write(|w| {
|
||||||
|
w.set_rnd_src_sel(self.config.inverter_chain_length.clone().into());
|
||||||
|
});
|
||||||
|
|
||||||
|
let sample_count_register = regs.sample_cnt1();
|
||||||
|
sample_count_register.write(|w| {
|
||||||
|
*w = self.config.sample_count;
|
||||||
|
});
|
||||||
|
|
||||||
|
let debug_control_register = regs.trng_debug_control();
|
||||||
|
debug_control_register.write(|w| {
|
||||||
|
w.set_auto_correlate_bypass(self.config.disable_autocorrelation_test);
|
||||||
|
w.set_trng_crngt_bypass(self.config.disable_crngt_test);
|
||||||
|
w.set_vnc_bypass(self.config.disable_von_neumann_balancer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn enable_irq(&self) {
|
fn enable_irq(&self) {
|
||||||
unsafe { T::Interrupt::enable() }
|
unsafe { T::Interrupt::enable() }
|
||||||
}
|
}
|
||||||
@ -218,6 +230,10 @@ impl<'d, T: Instance> Trng<'d, T> {
|
|||||||
if trng_valid_register.read().ehr_valid().not() {
|
if trng_valid_register.read().ehr_valid().not() {
|
||||||
if regs.rng_isr().read().autocorr_err() {
|
if regs.rng_isr().read().autocorr_err() {
|
||||||
regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true));
|
regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true));
|
||||||
|
// Fixed delay is required after TRNG soft reset. This read is sufficient.
|
||||||
|
regs.trng_sw_reset().read();
|
||||||
|
self.initialize_rng();
|
||||||
|
self.start_rng();
|
||||||
} else {
|
} else {
|
||||||
panic!("RNG not busy, but ehr is not valid!")
|
panic!("RNG not busy, but ehr is not valid!")
|
||||||
}
|
}
|
||||||
@ -279,8 +295,11 @@ impl<'d, T: Instance> Trng<'d, T> {
|
|||||||
if trng_busy_register.read().trng_busy() {
|
if trng_busy_register.read().trng_busy() {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
} else {
|
} else {
|
||||||
|
// If woken up and EHR is *not* valid, assume the trng has been reset and reinitialize, restart.
|
||||||
if trng_valid_register.read().ehr_valid().not() {
|
if trng_valid_register.read().ehr_valid().not() {
|
||||||
panic!("RNG not busy, but ehr is not valid!")
|
self.initialize_rng();
|
||||||
|
self.start_rng();
|
||||||
|
return Poll::Pending;
|
||||||
}
|
}
|
||||||
self.read_ehr_registers_into_array(&mut buffer);
|
self.read_ehr_registers_into_array(&mut buffer);
|
||||||
let remaining = destination_length - bytes_transferred;
|
let remaining = destination_length - bytes_transferred;
|
||||||
@ -380,25 +399,36 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let isr = regs.rng_isr().read();
|
let isr = regs.rng_isr().read();
|
||||||
// Clear ehr bit
|
|
||||||
regs.rng_icr().write(|w| {
|
|
||||||
w.set_ehr_valid(true);
|
|
||||||
});
|
|
||||||
if isr.ehr_valid() {
|
if isr.ehr_valid() {
|
||||||
|
regs.rng_icr().write(|w| {
|
||||||
|
w.set_ehr_valid(true);
|
||||||
|
});
|
||||||
T::waker().wake();
|
T::waker().wake();
|
||||||
} else {
|
} else if isr.crngt_err() {
|
||||||
|
warn!("TRNG CRNGT error! Increase sample count to reduce likelihood");
|
||||||
|
regs.rng_icr().write(|w| {
|
||||||
|
w.set_crngt_err(true);
|
||||||
|
});
|
||||||
|
} else if isr.vn_err() {
|
||||||
|
warn!("TRNG Von-Neumann balancer error! Increase sample count to reduce likelihood");
|
||||||
|
regs.rng_icr().write(|w| {
|
||||||
|
w.set_vn_err(true);
|
||||||
|
});
|
||||||
|
} else if isr.autocorr_err() {
|
||||||
// 12.12.5. List of Registers
|
// 12.12.5. List of Registers
|
||||||
// ...
|
// ...
|
||||||
// TRNG: RNG_ISR Register
|
// TRNG: RNG_ISR Register
|
||||||
// ...
|
// ...
|
||||||
// AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row.
|
// AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row.
|
||||||
// When set, RNG ceases functioning until next reset
|
// When set, RNG ceases functioning until next reset
|
||||||
if isr.autocorr_err() {
|
warn!("TRNG Autocorrect error! Resetting TRNG. Increase sample count to reduce likelihood");
|
||||||
warn!("TRNG Autocorrect error! Resetting TRNG");
|
regs.trng_sw_reset().write(|w| {
|
||||||
regs.trng_sw_reset().write(|w| {
|
w.set_trng_sw_reset(true);
|
||||||
w.set_trng_sw_reset(true);
|
});
|
||||||
});
|
// Fixed delay is required after TRNG soft reset, this read is sufficient.
|
||||||
}
|
regs.trng_sw_reset().read();
|
||||||
|
// Wake up to reinitialize and restart the TRNG.
|
||||||
|
T::waker().wake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user