aboutsummaryrefslogtreecommitdiff
path: root/embassy-mcxa/src/trng.rs
diff options
context:
space:
mode:
authorRaul Alimbekov <[email protected]>2025-12-16 09:05:22 +0300
committerGitHub <[email protected]>2025-12-16 09:05:22 +0300
commitc9a04b4b732b7a3b696eb8223664c1a7942b1875 (patch)
tree6dbe5c02e66eed8d8762f13f95afd24f8db2b38c /embassy-mcxa/src/trng.rs
parentcde24a3ef1117653ba5ed4184102b33f745782fb (diff)
parent5ae6e060ec1c90561719aabdc29d5b6e7b8b0a82 (diff)
Merge branch 'main' into main
Diffstat (limited to 'embassy-mcxa/src/trng.rs')
-rw-r--r--embassy-mcxa/src/trng.rs678
1 files changed, 678 insertions, 0 deletions
diff --git a/embassy-mcxa/src/trng.rs b/embassy-mcxa/src/trng.rs
new file mode 100644
index 000000000..ce37e4b2a
--- /dev/null
+++ b/embassy-mcxa/src/trng.rs
@@ -0,0 +1,678 @@
1//! True Random Number Generator
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::Peri;
6use embassy_hal_internal::interrupt::InterruptExt;
7use maitake_sync::WaitCell;
8use mcxa_pac::trng0::osc2_ctl::TrngEntCtl;
9
10use crate::clocks::enable_and_reset;
11use crate::clocks::periph_helpers::NoConfig;
12use crate::interrupt::typelevel;
13use crate::interrupt::typelevel::Handler;
14use crate::peripherals::TRNG0;
15
16static WAIT_CELL: WaitCell = WaitCell::new();
17
18#[allow(private_bounds)]
19pub trait Mode: sealed::SealedMode {}
20
21mod sealed {
22 pub trait SealedMode {}
23}
24
25macro_rules! define_mode {
26 ($mode:ident) => {
27 pub struct $mode;
28 impl sealed::SealedMode for $mode {}
29 impl Mode for $mode {}
30 };
31}
32
33define_mode!(Blocking);
34define_mode!(Async);
35
36/// TRNG Driver
37pub struct Trng<'d, M: Mode> {
38 _peri: Peri<'d, TRNG0>,
39 _phantom: PhantomData<M>,
40}
41
42impl<'d, M: Mode> Trng<'d, M> {
43 fn new_inner(_peri: Peri<'d, TRNG0>, config: Config) -> Self {
44 _ = unsafe { enable_and_reset::<TRNG0>(&NoConfig) };
45
46 Self::configure(config);
47 Self {
48 _peri,
49 _phantom: PhantomData,
50 }
51 }
52
53 fn configure(config: Config) {
54 regs()
55 .mctl()
56 .modify(|_, w| w.rst_def().set_bit().prgm().enable().err().clear_bit_by_one());
57
58 regs().scml().write(|w| unsafe {
59 w.mono_max()
60 .bits(config.monobit_limit_max)
61 .mono_rng()
62 .bits(config.monobit_limit_range)
63 });
64
65 regs().scr1l().write(|w| unsafe {
66 w.run1_max()
67 .bits(config.run_length1_limit_max)
68 .run1_rng()
69 .bits(config.run_length1_limit_range)
70 });
71
72 regs().scr2l().write(|w| unsafe {
73 w.run2_max()
74 .bits(config.run_length2_limit_max)
75 .run2_rng()
76 .bits(config.run_length2_limit_range)
77 });
78
79 regs().scr3l().write(|w| unsafe {
80 w.run3_max()
81 .bits(config.run_length3_limit_max)
82 .run3_rng()
83 .bits(config.run_length3_limit_range)
84 });
85
86 regs().scr4l().write(|w| unsafe {
87 w.run4_max()
88 .bits(config.run_length4_limit_max)
89 .run4_rng()
90 .bits(config.run_length4_limit_range)
91 });
92
93 regs().scr5l().write(|w| unsafe {
94 w.run5_max()
95 .bits(config.run_length5_limit_max)
96 .run5_rng()
97 .bits(config.run_length5_limit_range)
98 });
99
100 regs().scr6pl().write(|w| unsafe {
101 w.run6p_max()
102 .bits(config.run_length6_limit_max)
103 .run6p_rng()
104 .bits(config.run_length6_limit_range)
105 });
106
107 regs()
108 .pkrmax()
109 .write(|w| unsafe { w.pkr_max().bits(config.poker_limit_max) });
110
111 regs()
112 .frqmax()
113 .write(|w| unsafe { w.frq_max().bits(config.freq_counter_max) });
114
115 regs()
116 .frqmin()
117 .write(|w| unsafe { w.frq_min().bits(config.freq_counter_min) });
118
119 regs()
120 .sblim()
121 .write(|w| unsafe { w.sb_lim().bits(config.sparse_bit_limit) });
122
123 regs().scmisc().write(|w| unsafe {
124 w.lrun_max()
125 .bits(config.long_run_limit_max)
126 .rty_ct()
127 .bits(config.retry_count)
128 });
129
130 regs()
131 .mctl()
132 .modify(|_, w| w.dis_slf_tst().variant(config.self_test.into()));
133
134 regs().sdctl().write(|w| unsafe {
135 w.samp_size()
136 .bits(config.sample_size)
137 .ent_dly()
138 .bits(config.entropy_delay)
139 });
140
141 regs()
142 .osc2_ctl()
143 .modify(|_, w| w.trng_ent_ctl().variant(config.osc_mode.into()));
144
145 regs().mctl().modify(|_, w| w.prgm().disable());
146
147 let _ = regs().ent(7).read().bits();
148
149 Self::start();
150 }
151
152 fn start() {
153 regs().mctl().modify(|_, w| w.trng_acc().set_bit());
154 }
155
156 fn stop() {
157 regs().mctl().modify(|_, w| w.trng_acc().clear_bit());
158 }
159
160 fn blocking_wait_for_generation() {
161 while regs().mctl().read().ent_val().bit_is_clear() {
162 if regs().mctl().read().err().bit_is_set() {
163 regs().mctl().modify(|_, w| w.err().clear_bit_by_one());
164 }
165 }
166 }
167
168 fn fill_chunk(chunk: &mut [u8]) {
169 let mut entropy = [0u32; 8];
170
171 for (i, item) in entropy.iter_mut().enumerate() {
172 *item = regs().ent(i).read().bits();
173 }
174
175 let entropy: [u8; 32] = unsafe { core::mem::transmute(entropy) };
176
177 chunk.copy_from_slice(&entropy[..chunk.len()]);
178 }
179
180 // Blocking API
181
182 /// Fill the buffer with random bytes, blocking version.
183 pub fn blocking_fill_bytes(&mut self, buf: &mut [u8]) {
184 if buf.is_empty() {
185 return; // nothing to fill
186 }
187
188 for chunk in buf.chunks_mut(32) {
189 Self::blocking_wait_for_generation();
190 Self::fill_chunk(chunk);
191 }
192 }
193
194 /// Return a random u32, blocking version.
195 pub fn blocking_next_u32(&mut self) -> u32 {
196 Self::blocking_wait_for_generation();
197 // New random bytes are generated only after reading ENT7
198 regs().ent(7).read().bits()
199 }
200
201 /// Return a random u64, blocking version.
202 pub fn blocking_next_u64(&mut self) -> u64 {
203 Self::blocking_wait_for_generation();
204
205 let mut result = u64::from(regs().ent(6).read().bits()) << 32;
206 // New random bytes are generated only after reading ENT7
207 result |= u64::from(regs().ent(7).read().bits());
208 result
209 }
210}
211
212impl<'d> Trng<'d, Blocking> {
213 /// Instantiates a new TRNG peripheral driver with 128 samples of entropy.
214 pub fn new_blocking_128(_peri: Peri<'d, TRNG0>) -> Self {
215 Self::new_inner(
216 _peri,
217 Config {
218 sample_size: 128,
219 retry_count: 1,
220 long_run_limit_max: 29,
221 monobit_limit_max: 94,
222 monobit_limit_range: 61,
223 run_length1_limit_max: 39,
224 run_length1_limit_range: 39,
225 run_length2_limit_max: 24,
226 run_length2_limit_range: 25,
227 run_length3_limit_max: 17,
228 run_length3_limit_range: 18,
229 ..Default::default()
230 },
231 )
232 }
233
234 /// Instantiates a new TRNG peripheral driver with 256 samples of entropy.
235 pub fn new_blocking_256(_peri: Peri<'d, TRNG0>) -> Self {
236 Self::new_inner(
237 _peri,
238 Config {
239 sample_size: 256,
240 retry_count: 1,
241 long_run_limit_max: 31,
242 monobit_limit_max: 171,
243 monobit_limit_range: 86,
244 run_length1_limit_max: 63,
245 run_length1_limit_range: 56,
246 run_length2_limit_max: 38,
247 run_length2_limit_range: 38,
248 run_length3_limit_max: 25,
249 run_length3_limit_range: 26,
250 ..Default::default()
251 },
252 )
253 }
254
255 /// Instantiates a new TRNG peripheral driver with 512 samples of entropy.
256 pub fn new_blocking_512(_peri: Peri<'d, TRNG0>) -> Self {
257 Self::new_inner(_peri, Default::default())
258 }
259
260 /// Instantiates a new TRNG peripheral driver.
261 ///
262 /// NOTE: this constructor makes no attempt at validating the
263 /// parameters. If you get this wrong, the security guarantees of
264 /// the TRNG with regards to entropy may be violated
265 pub fn new_blocking_with_custom_config(_peri: Peri<'d, TRNG0>, config: Config) -> Self {
266 Self::new_inner(_peri, config)
267 }
268}
269
270impl<'d> Trng<'d, Async> {
271 /// Instantiates a new TRNG peripheral driver with 128 samples of entropy.
272 pub fn new_128(
273 _peri: Peri<'d, TRNG0>,
274 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
275 ) -> Self {
276 let inst = Self::new_inner(
277 _peri,
278 Config {
279 sample_size: 128,
280 retry_count: 1,
281 long_run_limit_max: 29,
282 monobit_limit_max: 94,
283 monobit_limit_range: 61,
284 run_length1_limit_max: 39,
285 run_length1_limit_range: 39,
286 run_length2_limit_max: 24,
287 run_length2_limit_range: 25,
288 run_length3_limit_max: 17,
289 run_length3_limit_range: 18,
290 ..Default::default()
291 },
292 );
293 crate::pac::Interrupt::TRNG0.unpend();
294 unsafe {
295 crate::pac::Interrupt::TRNG0.enable();
296 }
297 inst
298 }
299
300 /// Instantiates a new TRNG peripheral driver with 256 samples of entropy.
301 pub fn new_256(
302 _peri: Peri<'d, TRNG0>,
303 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
304 ) -> Self {
305 let inst = Self::new_inner(
306 _peri,
307 Config {
308 sample_size: 256,
309 retry_count: 1,
310 long_run_limit_max: 31,
311 monobit_limit_max: 171,
312 monobit_limit_range: 86,
313 run_length1_limit_max: 63,
314 run_length1_limit_range: 56,
315 run_length2_limit_max: 38,
316 run_length2_limit_range: 38,
317 run_length3_limit_max: 25,
318 run_length3_limit_range: 26,
319 ..Default::default()
320 },
321 );
322 crate::pac::Interrupt::TRNG0.unpend();
323 unsafe {
324 crate::pac::Interrupt::TRNG0.enable();
325 }
326 inst
327 }
328
329 /// Instantiates a new TRNG peripheral driver with 512 samples of entropy.
330 pub fn new_512(
331 _peri: Peri<'d, TRNG0>,
332 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
333 ) -> Self {
334 let inst = Self::new_inner(_peri, Default::default());
335 crate::pac::Interrupt::TRNG0.unpend();
336 unsafe {
337 crate::pac::Interrupt::TRNG0.enable();
338 }
339 inst
340 }
341
342 /// Instantiates a new TRNG peripheral driver.
343 ///
344 /// NOTE: this constructor makes no attempt at validating the
345 /// parameters. If you get this wrong, the security guarantees of
346 /// the TRNG with regards to entropy may be violated
347 pub fn new_with_custom_config(
348 _peri: Peri<'d, TRNG0>,
349 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
350 config: Config,
351 ) -> Self {
352 let inst = Self::new_inner(_peri, config);
353 crate::pac::Interrupt::TRNG0.unpend();
354 unsafe {
355 crate::pac::Interrupt::TRNG0.enable();
356 }
357 inst
358 }
359
360 fn enable_ints() {
361 regs().int_mask().write(|w| {
362 w.hw_err()
363 .set_bit()
364 .ent_val()
365 .set_bit()
366 .frq_ct_fail()
367 .set_bit()
368 .intg_flt()
369 .set_bit()
370 });
371 }
372
373 async fn wait_for_generation() -> Result<(), Error> {
374 WAIT_CELL
375 .wait_for(|| {
376 Self::enable_ints();
377 regs().mctl().read().ent_val().bit_is_set()
378 })
379 .await
380 .map_err(|_| Error::ErrorStatus)
381 }
382
383 // Async API
384
385 /// Fill the buffer with random bytes, async version.
386 pub async fn async_fill_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> {
387 if buf.is_empty() {
388 return Ok(()); // nothing to fill
389 }
390
391 for chunk in buf.chunks_mut(32) {
392 Self::wait_for_generation().await?;
393 Self::fill_chunk(chunk);
394 }
395
396 Ok(())
397 }
398
399 /// Return a random u32, async version.
400 pub async fn async_next_u32(&mut self) -> Result<u32, Error> {
401 Self::wait_for_generation().await?;
402 // New random bytes are generated only after reading ENT7
403 Ok(regs().ent(7).read().bits())
404 }
405
406 /// Return a random u64, async version.
407 pub async fn async_next_u64(&mut self) -> Result<u64, Error> {
408 Self::wait_for_generation().await?;
409
410 let mut result = u64::from(regs().ent(6).read().bits()) << 32;
411 // New random bytes are generated only after reading ENT7
412 result |= u64::from(regs().ent(7).read().bits());
413
414 Ok(result)
415 }
416}
417
418impl<M: Mode> Drop for Trng<'_, M> {
419 fn drop(&mut self) {
420 // wait until allowed to stop
421 while regs().mctl().read().tstop_ok().bit_is_clear() {}
422 // stop
423 Self::stop();
424 // reset the TRNG
425 regs().mctl().write(|w| w.rst_def().set_bit());
426 }
427}
428
429fn regs() -> &'static crate::pac::trng0::RegisterBlock {
430 unsafe { &*crate::pac::Trng0::ptr() }
431}
432
433/// Trng errors
434#[derive(Clone, Copy, Debug)]
435#[cfg_attr(feature = "defmt", derive(defmt::Format))]
436#[non_exhaustive]
437pub enum Error {
438 /// Integrity error.
439 IntegrityError,
440
441 /// Frequency counter fail
442 FrequencyCountFail,
443
444 /// Error status
445 ErrorStatus,
446
447 /// Buffer argument is invalid
448 InvalidBuffer,
449}
450
451/// TRNG interrupt handler.
452pub struct InterruptHandler;
453
454impl Handler<typelevel::TRNG0> for InterruptHandler {
455 unsafe fn on_interrupt() {
456 if regs().int_status().read().bits() != 0 {
457 regs().int_ctrl().write(|w| {
458 w.hw_err()
459 .clear_bit()
460 .ent_val()
461 .clear_bit()
462 .frq_ct_fail()
463 .clear_bit()
464 .intg_flt()
465 .clear_bit()
466 });
467 WAIT_CELL.wake();
468 }
469 }
470}
471
472/// True random number generator configuration parameters.
473#[derive(Clone, Copy, Debug)]
474#[cfg_attr(feature = "defmt", derive(defmt::Format))]
475#[non_exhaustive]
476pub struct Config {
477 /// Total number of Entropy samples that will be taken during
478 /// Entropy generation.
479 pub sample_size: u16,
480
481 /// Length (in system clocks) of each Entropy sample taken.
482 pub entropy_delay: u16,
483
484 /// Enable or disable internal self-tests.
485 pub self_test: SelfTest,
486
487 /// Frequency Counter Maximum Limit
488 pub freq_counter_max: u32,
489
490 /// Frequency Counter Minimum Limit
491 pub freq_counter_min: u32,
492
493 /// Statistical check monobit max limit
494 pub monobit_limit_max: u16,
495
496 /// Statistical check monobit range
497 pub monobit_limit_range: u16,
498
499 /// Statistical check run length 1 limit max
500 pub run_length1_limit_max: u16,
501
502 /// Statistical check run length 1 limit range
503 pub run_length1_limit_range: u16,
504
505 /// Statistical check run length 2 limit max
506 pub run_length2_limit_max: u16,
507
508 /// Statistical check run length 2 limit range
509 pub run_length2_limit_range: u16,
510
511 /// Statistical check run length 3 limit max
512 pub run_length3_limit_max: u16,
513
514 /// Statistical check run length 3 limit range
515 pub run_length3_limit_range: u16,
516
517 /// Statistical check run length 4 limit max
518 pub run_length4_limit_max: u16,
519
520 /// Statistical check run length 4 limit range
521 pub run_length4_limit_range: u16,
522
523 /// Statistical check run length 5 limit max
524 pub run_length5_limit_max: u16,
525
526 /// Statistical check run length 5 limit range
527 pub run_length5_limit_range: u16,
528
529 /// Statistical check run length 6 limit max
530 pub run_length6_limit_max: u16,
531
532 /// Statistical check run length 6 limit range
533 pub run_length6_limit_range: u16,
534
535 /// Retry count
536 pub retry_count: u8,
537
538 /// Long run limit max
539 pub long_run_limit_max: u8,
540
541 /// Sparse bit limit
542 pub sparse_bit_limit: u16,
543
544 /// Poker limit max
545 pub poker_limit_max: u32,
546
547 /// Oscillator mode
548 pub osc_mode: OscMode,
549}
550
551impl Default for Config {
552 fn default() -> Self {
553 Self {
554 sample_size: 512,
555 entropy_delay: 32_000,
556 self_test: SelfTest::Enabled,
557 freq_counter_max: 75_000,
558 freq_counter_min: 30_000,
559 monobit_limit_max: 317,
560 monobit_limit_range: 122,
561 run_length1_limit_max: 107,
562 run_length1_limit_range: 80,
563 run_length2_limit_max: 62,
564 run_length2_limit_range: 55,
565 run_length3_limit_max: 39,
566 run_length3_limit_range: 39,
567 run_length4_limit_max: 0,
568 run_length4_limit_range: 0,
569 run_length5_limit_max: 0,
570 run_length5_limit_range: 0,
571 run_length6_limit_max: 0,
572 run_length6_limit_range: 0,
573 retry_count: 1,
574 long_run_limit_max: 32,
575 sparse_bit_limit: 0,
576 poker_limit_max: 0,
577 osc_mode: OscMode::DualOscs,
578 }
579 }
580}
581
582/// Sample size.
583#[derive(Clone, Copy, Debug)]
584#[cfg_attr(feature = "defmt", derive(defmt::Format))]
585#[non_exhaustive]
586pub enum SampleSize {
587 /// 128 bits
588 _128,
589
590 /// 256 bits
591 _256,
592
593 /// 512 bits
594 _512,
595}
596
597/// Enable or disable internal self-tests.
598#[derive(Clone, Copy, Debug)]
599#[cfg_attr(feature = "defmt", derive(defmt::Format))]
600#[non_exhaustive]
601pub enum SelfTest {
602 /// Disabled.
603 Disabled,
604
605 /// Enabled.
606 Enabled,
607}
608
609impl From<SelfTest> for bool {
610 fn from(value: SelfTest) -> Self {
611 match value {
612 SelfTest::Disabled => true,
613 SelfTest::Enabled => false,
614 }
615 }
616}
617
618/// Oscillator mode.
619#[derive(Clone, Copy, Debug)]
620#[cfg_attr(feature = "defmt", derive(defmt::Format))]
621#[non_exhaustive]
622pub enum OscMode {
623 /// Single oscillator using OSC1.
624 SingleOsc1,
625
626 /// Dual oscillator.
627 DualOscs,
628
629 /// Single oscillator using OSC2.
630 SingleOsc2,
631}
632
633impl From<OscMode> for TrngEntCtl {
634 fn from(value: OscMode) -> Self {
635 match value {
636 OscMode::SingleOsc1 => Self::TrngEntCtlSingleOsc1,
637 OscMode::DualOscs => Self::TrngEntCtlDualOscs,
638 OscMode::SingleOsc2 => Self::TrngEntCtlSingleOsc2,
639 }
640 }
641}
642
643impl<'d, M: Mode> rand_core_06::RngCore for Trng<'d, M> {
644 fn next_u32(&mut self) -> u32 {
645 self.blocking_next_u32()
646 }
647
648 fn next_u64(&mut self) -> u64 {
649 self.blocking_next_u64()
650 }
651
652 fn fill_bytes(&mut self, dest: &mut [u8]) {
653 self.blocking_fill_bytes(dest);
654 }
655
656 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
657 self.blocking_fill_bytes(dest);
658 Ok(())
659 }
660}
661
662impl<'d, M: Mode> rand_core_06::CryptoRng for Trng<'d, M> {}
663
664impl<'d, M: Mode> rand_core_09::RngCore for Trng<'d, M> {
665 fn next_u32(&mut self) -> u32 {
666 self.blocking_next_u32()
667 }
668
669 fn next_u64(&mut self) -> u64 {
670 self.blocking_next_u64()
671 }
672
673 fn fill_bytes(&mut self, dest: &mut [u8]) {
674 self.blocking_fill_bytes(dest);
675 }
676}
677
678impl<'d, M: Mode> rand_core_09::CryptoRng for Trng<'d, M> {}