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