Skip to content

Commit 5ec42a6

Browse files
committed
lpc55-rng: Combine Lpc55Core and Lpc55Rng.
Implementing `BlockRngCore` for `Lpc55Core` got us an implementation of RngCore for free. Unfortunately it cost us the ability to return errors. This wasn't a good tradeoff. Better to implement `RngCore` directly.
1 parent 193d871 commit 5ec42a6

File tree

2 files changed

+45
-51
lines changed

2 files changed

+45
-51
lines changed

drv/lpc55-rng/src/main.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,7 @@ impl NotificationHandler for Lpc55RngServer {
131131

132132
#[export_name = "main"]
133133
fn main() -> ! {
134-
let rng = Lpc55Rng::new(Syscon::from(SYSCON.get_task_id()));
135-
rng.init();
134+
let rng = Lpc55Rng::new(&Syscon::from(SYSCON.get_task_id()));
136135

137136
let threshold = 0x100000; // 1 MiB
138137
let mut rng = Lpc55RngServer::new(rng, threshold)

lib/lpc55-rng/src/lib.rs

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,75 +5,70 @@
55
#![no_std]
66
#![no_main]
77

8+
use core::{cmp, mem};
89
use drv_lpc55_syscon_api::{Peripheral, Syscon};
910
use drv_rng_api::RngError;
1011
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};
1513

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,
2019
}
2120

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-
4321
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());
5427

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);
5631

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+
}
5936
}
6037
}
6138

6239
impl RngCore for Lpc55Rng {
40+
/// Get the next 4 bytes from the HRNG.
6341
fn next_u32(&mut self) -> u32 {
64-
self.0.next_u32()
42+
impls::next_u32_via_fill(self)
6543
}
44+
45+
/// Get the next 8 bytes from the HRNG.
6646
fn next_u64(&mut self) -> u64 {
67-
self.0.next_u64()
47+
impls::next_u64_via_fill(self)
6848
}
49+
50+
/// Fill the provided buffer with output from the HRNG.
6951
fn fill_bytes(&mut self, bytes: &mut [u8]) {
70-
self.0.fill_bytes(bytes)
52+
self.try_fill_bytes(bytes).expect("fill_bytes")
7153
}
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;
7570
}
7671

77-
self.0.try_fill_bytes(bytes)
72+
Ok(())
7873
}
7974
}

0 commit comments

Comments
 (0)