diff options
| -rw-r--r-- | embassy-rp/src/trng.rs | 104 |
1 files changed, 67 insertions, 37 deletions
diff --git a/embassy-rp/src/trng.rs b/embassy-rp/src/trng.rs index 611fee83b..a8a0172be 100644 --- a/embassy-rp/src/trng.rs +++ b/embassy-rp/src/trng.rs | |||
| @@ -78,6 +78,9 @@ impl From<InverterChainLength> for u8 { | |||
| 78 | /// failed entropy checks. | 78 | /// failed entropy checks. |
| 79 | /// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or | 79 | /// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or |
| 80 | /// 1 and sample count settings of 20-25. | 80 | /// 1 and sample count settings of 20-25. |
| 81 | /// Larger sample count settings (e.g. 100) provide proportionately slower average generation times. These settings | ||
| 82 | /// significantly reduce, but do not eliminate NIST test failures and entropy check failures. Results occasionally take an | ||
| 83 | /// especially long time to generate. | ||
| 81 | /// | 84 | /// |
| 82 | /// --- | 85 | /// --- |
| 83 | /// | 86 | /// |
| @@ -108,9 +111,10 @@ pub struct Config { | |||
| 108 | impl Default for Config { | 111 | impl Default for Config { |
| 109 | fn default() -> Self { | 112 | fn default() -> Self { |
| 110 | Config { | 113 | Config { |
| 111 | disable_autocorrelation_test: true, | 114 | // WARNING: Disabling these tests increases likelihood of poor rng results. |
| 112 | disable_crngt_test: true, | 115 | disable_autocorrelation_test: false, |
| 113 | disable_von_neumann_balancer: true, | 116 | disable_crngt_test: false, |
| 117 | disable_von_neumann_balancer: false, | ||
| 114 | sample_count: 25, | 118 | sample_count: 25, |
| 115 | inverter_chain_length: InverterChainLength::One, | 119 | inverter_chain_length: InverterChainLength::One, |
| 116 | } | 120 | } |
| @@ -148,6 +152,7 @@ impl Default for Config { | |||
| 148 | /// ``` | 152 | /// ``` |
| 149 | pub struct Trng<'d, T: Instance> { | 153 | pub struct Trng<'d, T: Instance> { |
| 150 | phantom: PhantomData<&'d mut T>, | 154 | phantom: PhantomData<&'d mut T>, |
| 155 | config: Config, | ||
| 151 | } | 156 | } |
| 152 | 157 | ||
| 153 | /// 12.12.1. Overview | 158 | /// 12.12.1. Overview |
| @@ -159,28 +164,12 @@ const TRNG_BLOCK_SIZE_BYTES: usize = TRNG_BLOCK_SIZE_BITS / 8; | |||
| 159 | impl<'d, T: Instance> Trng<'d, T> { | 164 | impl<'d, T: Instance> Trng<'d, T> { |
| 160 | /// Create a new TRNG driver. | 165 | /// Create a new TRNG driver. |
| 161 | pub fn new(_trng: Peri<'d, T>, _irq: impl Binding<T::Interrupt, InterruptHandler<T>> + 'd, config: Config) -> Self { | 166 | pub fn new(_trng: Peri<'d, T>, _irq: impl Binding<T::Interrupt, InterruptHandler<T>> + 'd, config: Config) -> Self { |
| 162 | let regs = T::regs(); | 167 | let trng = Trng { |
| 163 | 168 | phantom: PhantomData, | |
| 164 | regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false)); | 169 | config: config, |
| 165 | 170 | }; | |
| 166 | let trng_config_register = regs.trng_config(); | 171 | trng.initialize_rng(); |
| 167 | trng_config_register.write(|w| { | 172 | trng |
| 168 | w.set_rnd_src_sel(config.inverter_chain_length.clone().into()); | ||
| 169 | }); | ||
| 170 | |||
| 171 | let sample_count_register = regs.sample_cnt1(); | ||
| 172 | sample_count_register.write(|w| { | ||
| 173 | *w = config.sample_count; | ||
| 174 | }); | ||
| 175 | |||
| 176 | let debug_control_register = regs.trng_debug_control(); | ||
| 177 | debug_control_register.write(|w| { | ||
| 178 | w.set_auto_correlate_bypass(config.disable_autocorrelation_test); | ||
| 179 | w.set_trng_crngt_bypass(config.disable_crngt_test); | ||
| 180 | w.set_vnc_bypass(config.disable_von_neumann_balancer) | ||
| 181 | }); | ||
| 182 | |||
| 183 | Trng { phantom: PhantomData } | ||
| 184 | } | 173 | } |
| 185 | 174 | ||
| 186 | fn start_rng(&self) { | 175 | fn start_rng(&self) { |
| @@ -198,6 +187,29 @@ impl<'d, T: Instance> Trng<'d, T> { | |||
| 198 | reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true)); | 187 | reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true)); |
| 199 | } | 188 | } |
| 200 | 189 | ||
| 190 | fn initialize_rng(&self) { | ||
| 191 | let regs = T::regs(); | ||
| 192 | |||
| 193 | regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false)); | ||
| 194 | |||
| 195 | let trng_config_register = regs.trng_config(); | ||
| 196 | trng_config_register.write(|w| { | ||
| 197 | w.set_rnd_src_sel(self.config.inverter_chain_length.clone().into()); | ||
| 198 | }); | ||
| 199 | |||
| 200 | let sample_count_register = regs.sample_cnt1(); | ||
| 201 | sample_count_register.write(|w| { | ||
| 202 | *w = self.config.sample_count; | ||
| 203 | }); | ||
| 204 | |||
| 205 | let debug_control_register = regs.trng_debug_control(); | ||
| 206 | debug_control_register.write(|w| { | ||
| 207 | w.set_auto_correlate_bypass(self.config.disable_autocorrelation_test); | ||
| 208 | w.set_trng_crngt_bypass(self.config.disable_crngt_test); | ||
| 209 | w.set_vnc_bypass(self.config.disable_von_neumann_balancer); | ||
| 210 | }); | ||
| 211 | } | ||
| 212 | |||
| 201 | fn enable_irq(&self) { | 213 | fn enable_irq(&self) { |
| 202 | unsafe { T::Interrupt::enable() } | 214 | unsafe { T::Interrupt::enable() } |
| 203 | } | 215 | } |
| @@ -218,6 +230,10 @@ impl<'d, T: Instance> Trng<'d, T> { | |||
| 218 | if trng_valid_register.read().ehr_valid().not() { | 230 | if trng_valid_register.read().ehr_valid().not() { |
| 219 | if regs.rng_isr().read().autocorr_err() { | 231 | if regs.rng_isr().read().autocorr_err() { |
| 220 | regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true)); | 232 | regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true)); |
| 233 | // Fixed delay is required after TRNG soft reset. This read is sufficient. | ||
| 234 | regs.trng_sw_reset().read(); | ||
| 235 | self.initialize_rng(); | ||
| 236 | self.start_rng(); | ||
| 221 | } else { | 237 | } else { |
| 222 | panic!("RNG not busy, but ehr is not valid!") | 238 | panic!("RNG not busy, but ehr is not valid!") |
| 223 | } | 239 | } |
| @@ -279,8 +295,11 @@ impl<'d, T: Instance> Trng<'d, T> { | |||
| 279 | if trng_busy_register.read().trng_busy() { | 295 | if trng_busy_register.read().trng_busy() { |
| 280 | Poll::Pending | 296 | Poll::Pending |
| 281 | } else { | 297 | } else { |
| 298 | // If woken up and EHR is *not* valid, assume the trng has been reset and reinitialize, restart. | ||
| 282 | if trng_valid_register.read().ehr_valid().not() { | 299 | if trng_valid_register.read().ehr_valid().not() { |
| 283 | panic!("RNG not busy, but ehr is not valid!") | 300 | self.initialize_rng(); |
| 301 | self.start_rng(); | ||
| 302 | return Poll::Pending; | ||
| 284 | } | 303 | } |
| 285 | self.read_ehr_registers_into_array(&mut buffer); | 304 | self.read_ehr_registers_into_array(&mut buffer); |
| 286 | let remaining = destination_length - bytes_transferred; | 305 | let remaining = destination_length - bytes_transferred; |
| @@ -380,25 +399,36 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 380 | unsafe fn on_interrupt() { | 399 | unsafe fn on_interrupt() { |
| 381 | let regs = T::regs(); | 400 | let regs = T::regs(); |
| 382 | let isr = regs.rng_isr().read(); | 401 | let isr = regs.rng_isr().read(); |
| 383 | // Clear ehr bit | ||
| 384 | regs.rng_icr().write(|w| { | ||
| 385 | w.set_ehr_valid(true); | ||
| 386 | }); | ||
| 387 | if isr.ehr_valid() { | 402 | if isr.ehr_valid() { |
| 403 | regs.rng_icr().write(|w| { | ||
| 404 | w.set_ehr_valid(true); | ||
| 405 | }); | ||
| 388 | T::waker().wake(); | 406 | T::waker().wake(); |
| 389 | } else { | 407 | } else if isr.crngt_err() { |
| 408 | warn!("TRNG CRNGT error! Increase sample count to reduce likelihood"); | ||
| 409 | regs.rng_icr().write(|w| { | ||
| 410 | w.set_crngt_err(true); | ||
| 411 | }); | ||
| 412 | } else if isr.vn_err() { | ||
| 413 | warn!("TRNG Von-Neumann balancer error! Increase sample count to reduce likelihood"); | ||
| 414 | regs.rng_icr().write(|w| { | ||
| 415 | w.set_vn_err(true); | ||
| 416 | }); | ||
| 417 | } else if isr.autocorr_err() { | ||
| 390 | // 12.12.5. List of Registers | 418 | // 12.12.5. List of Registers |
| 391 | // ... | 419 | // ... |
| 392 | // TRNG: RNG_ISR Register | 420 | // TRNG: RNG_ISR Register |
| 393 | // ... | 421 | // ... |
| 394 | // AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row. | 422 | // AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row. |
| 395 | // When set, RNG ceases functioning until next reset | 423 | // When set, RNG ceases functioning until next reset |
| 396 | if isr.autocorr_err() { | 424 | warn!("TRNG Autocorrect error! Resetting TRNG. Increase sample count to reduce likelihood"); |
| 397 | warn!("TRNG Autocorrect error! Resetting TRNG"); | 425 | regs.trng_sw_reset().write(|w| { |
| 398 | regs.trng_sw_reset().write(|w| { | 426 | w.set_trng_sw_reset(true); |
| 399 | w.set_trng_sw_reset(true); | 427 | }); |
| 400 | }); | 428 | // Fixed delay is required after TRNG soft reset, this read is sufficient. |
| 401 | } | 429 | regs.trng_sw_reset().read(); |
| 430 | // Wake up to reinitialize and restart the TRNG. | ||
| 431 | T::waker().wake(); | ||
| 402 | } | 432 | } |
| 403 | } | 433 | } |
| 404 | } | 434 | } |
