aboutsummaryrefslogtreecommitdiff
path: root/embassy-imxrt
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-imxrt')
-rw-r--r--embassy-imxrt/src/lib.rs1
-rw-r--r--embassy-imxrt/src/rng.rs257
2 files changed, 258 insertions, 0 deletions
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs
index ad9f81e88..f728ba060 100644
--- a/embassy-imxrt/src/lib.rs
+++ b/embassy-imxrt/src/lib.rs
@@ -20,6 +20,7 @@ pub(crate) mod fmt;
20pub mod clocks; 20pub mod clocks;
21pub mod gpio; 21pub mod gpio;
22pub mod iopctl; 22pub mod iopctl;
23pub mod rng;
23 24
24#[cfg(feature = "_time-driver")] 25#[cfg(feature = "_time-driver")]
25pub mod time_driver; 26pub mod time_driver;
diff --git a/embassy-imxrt/src/rng.rs b/embassy-imxrt/src/rng.rs
new file mode 100644
index 000000000..67e7ab65d
--- /dev/null
+++ b/embassy-imxrt/src/rng.rs
@@ -0,0 +1,257 @@
1//! True Random Number Generator (TRNG)
2
3use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::task::Poll;
6
7use embassy_futures::block_on;
8use embassy_sync::waitqueue::AtomicWaker;
9use rand_core::{CryptoRng, RngCore};
10
11use crate::clocks::{enable_and_reset, SysconPeripheral};
12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, peripherals, Peri, PeripheralType};
14
15static RNG_WAKER: AtomicWaker = AtomicWaker::new();
16
17/// RNG ;error
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Error {
21 /// Seed error.
22 SeedError,
23
24 /// HW Error.
25 HwError,
26
27 /// Frequency Count Fail
28 FreqCountFail,
29}
30
31/// RNG interrupt handler.
32pub struct InterruptHandler<T: Instance> {
33 _phantom: PhantomData<T>,
34}
35
36impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
37 unsafe fn on_interrupt() {
38 let regs = T::info().regs;
39 let int_status = regs.int_status().read();
40
41 if int_status.ent_val().bit_is_set()
42 || int_status.hw_err().bit_is_set()
43 || int_status.frq_ct_fail().bit_is_set()
44 {
45 regs.int_ctrl().modify(|_, w| {
46 w.ent_val()
47 .ent_val_0()
48 .hw_err()
49 .hw_err_0()
50 .frq_ct_fail()
51 .frq_ct_fail_0()
52 });
53 RNG_WAKER.wake();
54 }
55 }
56}
57
58/// RNG driver.
59pub struct Rng<'d> {
60 info: Info,
61 _lifetime: PhantomData<&'d ()>,
62}
63
64impl<'d> Rng<'d> {
65 /// Create a new RNG driver.
66 pub fn new<T: Instance>(
67 _inner: Peri<'d, T>,
68 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
69 ) -> Self {
70 enable_and_reset::<T>();
71
72 let mut random = Self {
73 info: T::info(),
74 _lifetime: PhantomData,
75 };
76 random.init();
77
78 T::Interrupt::unpend();
79 unsafe { T::Interrupt::enable() };
80
81 random
82 }
83
84 /// Reset the RNG.
85 pub fn reset(&mut self) {
86 self.info.regs.mctl().write(|w| w.rst_def().set_bit().prgm().set_bit());
87 }
88
89 /// Fill the given slice with random values.
90 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
91 // We have a total of 16 words (512 bits) of entropy at our
92 // disposal. The idea here is to read all bits and copy the
93 // necessary bytes to the slice.
94 for chunk in dest.chunks_mut(64) {
95 self.async_fill_chunk(chunk).await?;
96 }
97
98 Ok(())
99 }
100
101 async fn async_fill_chunk(&mut self, chunk: &mut [u8]) -> Result<(), Error> {
102 // wait for interrupt
103 let res = poll_fn(|cx| {
104 // Check if already ready.
105 // TODO: Is this necessary? Could we just check once after
106 // the waker has been registered?
107 if self.info.regs.int_status().read().ent_val().bit_is_set() {
108 return Poll::Ready(Ok(()));
109 }
110
111 RNG_WAKER.register(cx.waker());
112
113 self.unmask_interrupts();
114
115 let mctl = self.info.regs.mctl().read();
116
117 // Check again if interrupt fired
118 if mctl.ent_val().bit_is_set() {
119 Poll::Ready(Ok(()))
120 } else if mctl.err().bit_is_set() {
121 Poll::Ready(Err(Error::HwError))
122 } else if mctl.fct_fail().bit_is_set() {
123 Poll::Ready(Err(Error::FreqCountFail))
124 } else {
125 Poll::Pending
126 }
127 })
128 .await;
129
130 let bits = self.info.regs.mctl().read();
131
132 if bits.ent_val().bit_is_set() {
133 let mut entropy = [0; 16];
134
135 for (i, item) in entropy.iter_mut().enumerate() {
136 *item = self.info.regs.ent(i).read().bits();
137 }
138
139 // Read MCTL after reading ENT15
140 let _ = self.info.regs.mctl().read();
141
142 if entropy.iter().any(|e| *e == 0) {
143 return Err(Error::SeedError);
144 }
145
146 // SAFETY: entropy is the same for input and output types in
147 // native endianness.
148 let entropy: [u8; 64] = unsafe { core::mem::transmute(entropy) };
149
150 // write bytes to chunk
151 chunk.copy_from_slice(&entropy[..chunk.len()]);
152 }
153
154 res
155 }
156
157 fn mask_interrupts(&mut self) {
158 self.info.regs.int_mask().write(|w| {
159 w.ent_val()
160 .ent_val_0()
161 .hw_err()
162 .hw_err_0()
163 .frq_ct_fail()
164 .frq_ct_fail_0()
165 });
166 }
167
168 fn unmask_interrupts(&mut self) {
169 self.info.regs.int_mask().modify(|_, w| {
170 w.ent_val()
171 .ent_val_1()
172 .hw_err()
173 .hw_err_1()
174 .frq_ct_fail()
175 .frq_ct_fail_1()
176 });
177 }
178
179 fn enable_interrupts(&mut self) {
180 self.info.regs.int_ctrl().write(|w| {
181 w.ent_val()
182 .ent_val_1()
183 .hw_err()
184 .hw_err_1()
185 .frq_ct_fail()
186 .frq_ct_fail_1()
187 });
188 }
189
190 fn init(&mut self) {
191 self.mask_interrupts();
192
193 // Switch TRNG to programming mode
194 self.info.regs.mctl().modify(|_, w| w.prgm().set_bit());
195
196 self.enable_interrupts();
197
198 // Switch TRNG to Run Mode
199 self.info
200 .regs
201 .mctl()
202 .modify(|_, w| w.trng_acc().set_bit().prgm().clear_bit());
203 }
204}
205
206impl RngCore for Rng<'_> {
207 fn next_u32(&mut self) -> u32 {
208 let mut bytes = [0u8; 4];
209 block_on(self.async_fill_bytes(&mut bytes)).unwrap();
210 u32::from_ne_bytes(bytes)
211 }
212
213 fn next_u64(&mut self) -> u64 {
214 let mut bytes = [0u8; 8];
215 block_on(self.async_fill_bytes(&mut bytes)).unwrap();
216 u64::from_ne_bytes(bytes)
217 }
218
219 fn fill_bytes(&mut self, dest: &mut [u8]) {
220 block_on(self.async_fill_bytes(dest)).unwrap();
221 }
222
223 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
224 self.fill_bytes(dest);
225 Ok(())
226 }
227}
228
229impl CryptoRng for Rng<'_> {}
230
231struct Info {
232 regs: crate::pac::Trng,
233}
234
235trait SealedInstance {
236 fn info() -> Info;
237}
238
239/// RNG instance trait.
240#[allow(private_bounds)]
241pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {
242 /// Interrupt for this RNG instance.
243 type Interrupt: interrupt::typelevel::Interrupt;
244}
245
246impl Instance for peripherals::RNG {
247 type Interrupt = crate::interrupt::typelevel::RNG;
248}
249
250impl SealedInstance for peripherals::RNG {
251 fn info() -> Info {
252 // SAFETY: safe from single executor
253 Info {
254 regs: unsafe { crate::pac::Trng::steal() },
255 }
256 }
257}