|
5 | 5 | #![no_std]
|
6 | 6 | #![no_main]
|
7 | 7 |
|
| 8 | +use core::{cmp, mem}; |
8 | 9 | use drv_lpc55_syscon_api::{Peripheral, Syscon};
|
9 | 10 | use drv_rng_api::RngError;
|
10 | 11 | use lpc55_pac::{pmc, rng, PMC, RNG};
|
11 |
| -use rand_core::{ |
12 |
| - block::{BlockRng, BlockRngCore}, |
13 |
| - Error, RngCore, |
14 |
| -}; |
| 12 | +use rand_core::{impls, Error, RngCore}; |
15 | 13 |
|
16 |
| -struct Lpc55Core { |
17 |
| - pmc: &'static pmc::RegisterBlock, |
18 |
| - rng: &'static rng::RegisterBlock, |
19 |
| - syscon: Syscon, |
| 14 | +/// The Lpc55Rng is a thin wrapper around the LPC55 hardware randome number |
| 15 | +/// generator (HRNG). |
| 16 | +pub struct Lpc55Rng { |
| 17 | + pub pmc: &'static pmc::RegisterBlock, |
| 18 | + pub rng: &'static rng::RegisterBlock, |
20 | 19 | }
|
21 | 20 |
|
22 |
| -impl Lpc55Core { |
23 |
| - fn new(syscon: Syscon) -> Self { |
24 |
| - Lpc55Core { |
25 |
| - pmc: unsafe { &*PMC::ptr() }, |
26 |
| - rng: unsafe { &*RNG::ptr() }, |
27 |
| - syscon, |
28 |
| - } |
29 |
| - } |
30 |
| -} |
31 |
| - |
32 |
| -impl BlockRngCore for Lpc55Core { |
33 |
| - type Item = u32; |
34 |
| - type Results = [u32; 1]; |
35 |
| - |
36 |
| - fn generate(&mut self, results: &mut Self::Results) { |
37 |
| - results[0] = self.rng.random_number.read().bits(); |
38 |
| - } |
39 |
| -} |
40 |
| - |
41 |
| -pub struct Lpc55Rng(BlockRng<Lpc55Core>); |
42 |
| - |
43 | 21 | impl Lpc55Rng {
|
44 |
| - pub fn new(syscon: Syscon) -> Self { |
45 |
| - Lpc55Rng(BlockRng::new(Lpc55Core::new(syscon))) |
46 |
| - } |
47 |
| - |
48 |
| - pub fn init(&self) { |
49 |
| - self.0 |
50 |
| - .core |
51 |
| - .pmc |
52 |
| - .pdruncfg0 |
53 |
| - .modify(|_, w| w.pden_rng().poweredon()); |
| 22 | + /// Create a new Lpc55Rng instance after powering on, enabling the clocks |
| 23 | + /// and reseting the underlying HRNG. |
| 24 | + pub fn new(syscon: &Syscon) -> Self { |
| 25 | + let pmc = unsafe { &*PMC::ptr() }; |
| 26 | + pmc.pdruncfg0.modify(|_, w| w.pden_rng().poweredon()); |
54 | 27 |
|
55 |
| - self.0.core.syscon.enable_clock(Peripheral::Rng); |
| 28 | + syscon.enable_clock(Peripheral::Rng); |
| 29 | + syscon.enter_reset(Peripheral::Rng); |
| 30 | + syscon.leave_reset(Peripheral::Rng); |
56 | 31 |
|
57 |
| - self.0.core.syscon.enter_reset(Peripheral::Rng); |
58 |
| - self.0.core.syscon.leave_reset(Peripheral::Rng); |
| 32 | + Lpc55Rng { |
| 33 | + pmc, |
| 34 | + rng: unsafe { &*RNG::ptr() }, |
| 35 | + } |
59 | 36 | }
|
60 | 37 | }
|
61 | 38 |
|
62 | 39 | impl RngCore for Lpc55Rng {
|
| 40 | + /// Get the next 4 bytes from the HRNG. |
63 | 41 | fn next_u32(&mut self) -> u32 {
|
64 |
| - self.0.next_u32() |
| 42 | + impls::next_u32_via_fill(self) |
65 | 43 | }
|
| 44 | + |
| 45 | + /// Get the next 8 bytes from the HRNG. |
66 | 46 | fn next_u64(&mut self) -> u64 {
|
67 |
| - self.0.next_u64() |
| 47 | + impls::next_u64_via_fill(self) |
68 | 48 | }
|
| 49 | + |
| 50 | + /// Fill the provided buffer with output from the HRNG. |
69 | 51 | fn fill_bytes(&mut self, bytes: &mut [u8]) {
|
70 |
| - self.0.fill_bytes(bytes) |
| 52 | + self.try_fill_bytes(bytes).expect("fill_bytes") |
71 | 53 | }
|
72 |
| - fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> { |
73 |
| - if self.0.core.pmc.pdruncfg0.read().pden_rng().bits() { |
74 |
| - return Err(RngError::PoweredOff.into()); |
| 54 | + |
| 55 | + /// Fill the provided buffer with output from the HRNG. If the HRNG |
| 56 | + /// can't service the request an error is returned. |
| 57 | + fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Error> { |
| 58 | + let mut filled = 0; |
| 59 | + while filled < dst.len() { |
| 60 | + if self.pmc.pdruncfg0.read().pden_rng().bits() { |
| 61 | + return Err(RngError::PoweredOff.into()); |
| 62 | + } |
| 63 | + |
| 64 | + let src = self.rng.random_number.read().bits(); |
| 65 | + let len = cmp::min(mem::size_of_val(&src), dst[filled..].len()); |
| 66 | + |
| 67 | + dst[filled..filled + len] |
| 68 | + .copy_from_slice(&src.to_le_bytes()[..len]); |
| 69 | + filled += len; |
75 | 70 | }
|
76 | 71 |
|
77 |
| - self.0.try_fill_bytes(bytes) |
| 72 | + Ok(()) |
78 | 73 | }
|
79 | 74 | }
|
0 commit comments