aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp
diff options
context:
space:
mode:
authorLuke Rindels <[email protected]>2025-04-27 13:19:14 -0700
committerLuke Rindels <[email protected]>2025-04-27 15:25:23 -0700
commitcdef573f529c49d27a1daace3fc0c7a5d38b05de (patch)
tree6accb7b99622bb972615db57594ed8bd718fe407 /embassy-rp
parent9ab6100577eab3a23ac0c47fd74dc7a696d94837 (diff)
Enable rp235x trng self-tests by default
Gracefully handle rp235x trng self-test errors and resets
Diffstat (limited to 'embassy-rp')
-rw-r--r--embassy-rp/src/trng.rs104
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 {
108impl Default for Config { 111impl 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/// ```
149pub struct Trng<'d, T: Instance> { 153pub 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;
159impl<'d, T: Instance> Trng<'d, T> { 164impl<'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}